terraspace 0.5.9 → 0.6.1
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/.github/ISSUE_TEMPLATE.md +2 -2
- data/.github/ISSUE_TEMPLATE/bug_report.md +4 -3
- data/.github/ISSUE_TEMPLATE/question.md +2 -2
- data/CHANGELOG.md +29 -7
- data/README.md +2 -0
- data/lib/terraspace.rb +1 -0
- data/lib/terraspace/app.rb +36 -16
- data/lib/terraspace/app/inits.rb +13 -0
- data/lib/terraspace/booter.rb +1 -0
- data/lib/terraspace/cli.rb +13 -6
- data/lib/terraspace/cli/build/placeholder.rb +6 -1
- data/lib/terraspace/cli/commander.rb +1 -1
- data/lib/terraspace/cli/down.rb +1 -1
- data/lib/terraspace/cli/help/{cloud → tfc}/destroy.md +1 -1
- data/lib/terraspace/cli/help/{cloud → tfc}/list.md +1 -1
- data/lib/terraspace/cli/help/{cloud → tfc}/runs/list.md +3 -3
- data/lib/terraspace/cli/help/{cloud → tfc}/runs/prune.md +3 -3
- data/lib/terraspace/cli/help/{cloud → tfc}/sync.md +3 -3
- data/lib/terraspace/cli/init.rb +21 -8
- data/lib/terraspace/cli/state.rb +10 -0
- data/lib/terraspace/cli/{cloud.rb → tfc.rb} +3 -3
- data/lib/terraspace/cli/{cloud → tfc}/runs.rb +4 -4
- data/lib/terraspace/cli/up.rb +5 -3
- data/lib/terraspace/compiler/builder.rb +2 -0
- data/lib/terraspace/compiler/dirs_concern.rb +11 -1
- data/lib/terraspace/compiler/select.rb +28 -0
- data/lib/terraspace/compiler/strategy/tfvar.rb +16 -4
- data/lib/terraspace/compiler/strategy/tfvar/layer.rb +75 -52
- data/lib/terraspace/layering.rb +24 -0
- data/lib/terraspace/logger.rb +8 -1
- data/lib/terraspace/mod.rb +18 -3
- data/lib/terraspace/plugin/expander/friendly.rb +10 -0
- data/lib/terraspace/plugin/expander/interface.rb +6 -1
- data/lib/terraspace/plugin/summary/interface.rb +1 -1
- data/lib/terraspace/shell.rb +16 -1
- data/lib/terraspace/shell/error.rb +1 -1
- data/lib/terraspace/terraform/api/runs.rb +13 -2
- data/lib/terraspace/terraform/api/token.rb +2 -2
- data/lib/terraspace/terraform/api/var.rb +1 -1
- data/lib/terraspace/terraform/api/vars.rb +1 -1
- data/lib/terraspace/terraform/api/vars/base.rb +2 -0
- data/lib/terraspace/terraform/api/vars/json.rb +13 -1
- data/lib/terraspace/terraform/api/workspace.rb +10 -3
- data/lib/terraspace/terraform/args/default.rb +23 -13
- data/lib/terraspace/terraform/ihooks/after/plan.rb +17 -0
- data/lib/terraspace/terraform/ihooks/base.rb +8 -0
- data/lib/terraspace/terraform/ihooks/before/plan.rb +14 -0
- data/lib/terraspace/terraform/remote_state/fetcher.rb +1 -1
- data/lib/terraspace/terraform/runner.rb +12 -0
- data/lib/terraspace/terraform/{cloud → tfc}/runs.rb +1 -1
- data/lib/terraspace/terraform/{cloud → tfc}/runs/base.rb +1 -1
- data/lib/terraspace/terraform/{cloud → tfc}/runs/item_presenter.rb +1 -1
- data/lib/terraspace/terraform/{cloud → tfc}/runs/lister.rb +1 -1
- data/lib/terraspace/terraform/{cloud → tfc}/runs/pruner.rb +1 -1
- data/lib/terraspace/terraform/{cloud → tfc}/sync.rb +2 -2
- data/lib/terraspace/terraform/{cloud → tfc}/syncer.rb +1 -1
- data/lib/terraspace/terraform/{cloud → tfc}/workspace.rb +2 -3
- data/lib/terraspace/util/pretty.rb +2 -1
- data/lib/terraspace/version.rb +1 -1
- metadata +26 -18
@@ -0,0 +1,10 @@
|
|
1
|
+
class Terraspace::CLI
|
2
|
+
class State < Base
|
3
|
+
def run
|
4
|
+
@name = "state #{@options[:subcommand]}" # command name. IE: state list
|
5
|
+
Terraspace::Builder.new(@options).run
|
6
|
+
Init.new(@options).run
|
7
|
+
Terraspace::Terraform::Runner.new(@name, @options).run
|
8
|
+
end
|
9
|
+
end
|
10
|
+
end
|
@@ -1,7 +1,7 @@
|
|
1
1
|
class Terraspace::CLI
|
2
|
-
class
|
3
|
-
Syncer = Terraspace::Terraform::
|
4
|
-
Workspace = Terraspace::Terraform::
|
2
|
+
class Tfc < Terraspace::Command
|
3
|
+
Syncer = Terraspace::Terraform::Tfc::Syncer
|
4
|
+
Workspace = Terraspace::Terraform::Tfc::Workspace
|
5
5
|
|
6
6
|
yes_option = Proc.new {
|
7
7
|
option :yes, aliases: :y, type: :boolean, desc: "bypass are you sure prompt"
|
@@ -1,10 +1,10 @@
|
|
1
|
-
class Terraspace::CLI::
|
1
|
+
class Terraspace::CLI::Tfc
|
2
2
|
class Runs < Terraspace::Command
|
3
3
|
Help = Terraspace::CLI::Help
|
4
|
-
Runs = Terraspace::Terraform::
|
4
|
+
Runs = Terraspace::Terraform::Tfc::Runs
|
5
5
|
|
6
6
|
desc "list STACK", "List runs."
|
7
|
-
long_desc Help.text("
|
7
|
+
long_desc Help.text("tfc:runs:list")
|
8
8
|
option :format, desc: "Output formats: #{CliFormat.formats.join(', ')}"
|
9
9
|
option :status, default: %w[pending planned], type: :array, desc: "Filter by statuses: pending, planned, all"
|
10
10
|
def list(mod)
|
@@ -12,7 +12,7 @@ class Terraspace::CLI::Cloud
|
|
12
12
|
end
|
13
13
|
|
14
14
|
desc "prune STACK", "Prune runs that are possible to cancel or discard."
|
15
|
-
long_desc Help.text("
|
15
|
+
long_desc Help.text("tfc:runs:prune")
|
16
16
|
option :noop, type: :boolean, desc: "Shows what would be cancelled/discarded."
|
17
17
|
option :yes, aliases: :y, type: :boolean, desc: "bypass are you sure prompt"
|
18
18
|
def prune(mod)
|
data/lib/terraspace/cli/up.rb
CHANGED
@@ -1,10 +1,12 @@
|
|
1
|
+
require 'securerandom'
|
2
|
+
|
1
3
|
class Terraspace::CLI
|
2
4
|
class Up < Base
|
3
5
|
include TfcConcern
|
4
6
|
|
5
7
|
def run
|
6
8
|
build
|
7
|
-
if @options[:yes] && !tfc?
|
9
|
+
if @options[:yes] && !@options[:plan] && !tfc?
|
8
10
|
plan
|
9
11
|
Commander.new("apply", @options.merge(plan: plan_path)).run
|
10
12
|
else
|
@@ -25,8 +27,8 @@ class Terraspace::CLI
|
|
25
27
|
end
|
26
28
|
|
27
29
|
def plan_path
|
28
|
-
@@
|
29
|
-
"#{Terraspace.tmp_root}/plans/#{@mod.name}-#{@@
|
30
|
+
@@random ||= SecureRandom.hex
|
31
|
+
"#{Terraspace.tmp_root}/plans/#{@mod.name}-#{@@random}.plan"
|
30
32
|
end
|
31
33
|
end
|
32
34
|
end
|
@@ -39,6 +39,7 @@ module Terraspace::Compiler
|
|
39
39
|
expr = "#{Terraspace.root}/config/terraform/**/*"
|
40
40
|
Dir.glob(expr).each do |path|
|
41
41
|
next unless File.file?(path)
|
42
|
+
next if path.include?('config/terraform/tfvars')
|
42
43
|
build_config_file(basename(path))
|
43
44
|
end
|
44
45
|
end
|
@@ -73,6 +74,7 @@ module Terraspace::Compiler
|
|
73
74
|
def skip?(src_path)
|
74
75
|
return true unless File.file?(src_path)
|
75
76
|
# certain folders will be skipped
|
77
|
+
src_path.include?("#{@mod.root}/tfvars") ||
|
76
78
|
src_path.include?("#{@mod.root}/config/args") ||
|
77
79
|
src_path.include?("#{@mod.root}/config/hooks") ||
|
78
80
|
src_path.include?("#{@mod.root}/test")
|
@@ -23,6 +23,7 @@ module Terraspace::Compiler
|
|
23
23
|
names, built = [], []
|
24
24
|
local_paths(type_dir).each do |path|
|
25
25
|
next unless File.directory?(path)
|
26
|
+
next unless select_stack?(type_dir, path)
|
26
27
|
mod_name = File.basename(path)
|
27
28
|
next if built.include?(mod_name) # ensures modules in app folder take higher precedence than vendor folder
|
28
29
|
names << mod_name
|
@@ -31,6 +32,15 @@ module Terraspace::Compiler
|
|
31
32
|
end
|
32
33
|
memoize :mod_names
|
33
34
|
|
35
|
+
# Examples:
|
36
|
+
# type_dir stacks
|
37
|
+
# path /home/ec2-user/environment/downloads/infra/app/stacks/demo
|
38
|
+
def select_stack?(type_dir, path)
|
39
|
+
return true unless type_dir == "stacks"
|
40
|
+
select = Terraspace::Compiler::Select.new(path)
|
41
|
+
select.selected?
|
42
|
+
end
|
43
|
+
|
34
44
|
def local_paths(type_dir)
|
35
45
|
dirs("app/#{type_dir}/*") + dirs("vendor/#{type_dir}/*")
|
36
46
|
end
|
@@ -40,7 +50,7 @@ module Terraspace::Compiler
|
|
40
50
|
end
|
41
51
|
|
42
52
|
def stack_names
|
43
|
-
mod_names("stacks")
|
53
|
+
mod_names("stacks")
|
44
54
|
end
|
45
55
|
memoize :stack_names
|
46
56
|
end
|
@@ -0,0 +1,28 @@
|
|
1
|
+
module Terraspace::Compiler
|
2
|
+
class Select
|
3
|
+
def initialize(path)
|
4
|
+
@path = path
|
5
|
+
@stack_name = extract_stack_name(path)
|
6
|
+
end
|
7
|
+
|
8
|
+
def selected?
|
9
|
+
all = Terraspace.config.all
|
10
|
+
# Key difference between include_stacks vs all.include_stacks option is that
|
11
|
+
# the option can be nil. The local variable is guaranteed to be an Array.
|
12
|
+
# This simplifies the logic.
|
13
|
+
include_stacks = all.include_stacks || []
|
14
|
+
ignore_stacks = all.ignore_stacks || []
|
15
|
+
|
16
|
+
if all.include_stacks.nil?
|
17
|
+
!ignore_stacks.include?(@stack_name)
|
18
|
+
else
|
19
|
+
stacks = include_stacks - ignore_stacks
|
20
|
+
stacks.include?(@stack_name)
|
21
|
+
end
|
22
|
+
end
|
23
|
+
|
24
|
+
def extract_stack_name(path)
|
25
|
+
path.sub(%r{.*(app|vendor)/stacks/}, '')
|
26
|
+
end
|
27
|
+
end
|
28
|
+
end
|
@@ -20,18 +20,30 @@ module Terraspace::Compiler::Strategy
|
|
20
20
|
end
|
21
21
|
end
|
22
22
|
|
23
|
+
def layer_paths
|
24
|
+
Layer.new(@mod).paths
|
25
|
+
end
|
26
|
+
|
23
27
|
# Tact on number to ensure that tfvars will be processed in desired order.
|
24
28
|
# Also name auto.tfvars so it will automatically load
|
25
29
|
def ordered_name(layer_path)
|
26
30
|
@order += 1
|
27
|
-
prefix = @order.to_s
|
28
|
-
|
31
|
+
prefix = @order.to_s
|
32
|
+
# add leading 0 when more than 10 layers
|
33
|
+
prefix = prefix.rjust(2, '0') if layer_paths.size > 9
|
34
|
+
name = "#{prefix}-#{tfvar_name(layer_path)}"
|
29
35
|
name.sub('.tfvars','.auto.tfvars')
|
30
36
|
.sub('.rb','.auto.tfvars.json')
|
31
37
|
end
|
32
38
|
|
33
|
-
def
|
34
|
-
|
39
|
+
def tfvar_name(layer_path)
|
40
|
+
if layer_path.include?('/tfvars/')
|
41
|
+
name = layer_path.sub(%r{.*/tfvars/},'').gsub('/','-')
|
42
|
+
name = "project-#{name}" if layer_path.include?("config/terraform/tfvars")
|
43
|
+
name
|
44
|
+
else
|
45
|
+
File.basename(layer_path)
|
46
|
+
end
|
35
47
|
end
|
36
48
|
|
37
49
|
def strategy_class(ext)
|
@@ -1,11 +1,51 @@
|
|
1
|
+
# Layers in order
|
2
|
+
#
|
3
|
+
# Name / Pattern | Example
|
4
|
+
# -------------------------------|---------------
|
5
|
+
# base | base.tfvars
|
6
|
+
# env | dev.tfvars
|
7
|
+
# region/base | us-west-2/base.tfvars (provider specific)
|
8
|
+
# region/env | us-west-2/dev.tfvars (provider specific)
|
9
|
+
# namespace/base | 112233445566/base.tfvars (provider specific)
|
10
|
+
# namespace/env | 112233445566/dev.tfvars (provider specific)
|
11
|
+
# namespace/region/base | 112233445566/us-west-2/base.tfvars (provider specific)
|
12
|
+
# namespace/region/env | 112233445566/us-west-2/dev.tfvars (provider specific)
|
13
|
+
# provider/base | aws/base.tfvars (provider specific)
|
14
|
+
# provider/env | aws/dev.tfvars (provider specific)
|
15
|
+
# provider/region/base | aws/us-west-2/base.tfvars (provider specific)
|
16
|
+
# provider/region/env | aws/us-west-2/dev.tfvars (provider specific)
|
17
|
+
# provider/namespace/base | aws/112233445566/base.tfvars (provider specific)
|
18
|
+
# provider/namespace/env | aws/112233445566/dev.tfvars (provider specific)
|
19
|
+
# provider/namespace/region/base | aws/112233445566/us-west-2/base.tfvars (provider specific)
|
20
|
+
# provider/namespace/region/env | aws/112233445566/us-west-2/dev.tfvars (provider specific)
|
21
|
+
#
|
22
|
+
# namespace and region depends on the provider. Here an example of the mapping:
|
23
|
+
#
|
24
|
+
# | AWS | Azure | Google
|
25
|
+
# ----------|---------|--------------|-------
|
26
|
+
# namespace | account | subscription | project
|
27
|
+
# region | region | location | region
|
28
|
+
#
|
29
|
+
#
|
1
30
|
class Terraspace::Compiler::Strategy::Tfvar
|
2
31
|
class Layer
|
32
|
+
extend Memoist
|
33
|
+
include Terraspace::Layering
|
34
|
+
include Terraspace::Plugin::Expander::Friendly
|
35
|
+
|
3
36
|
def initialize(mod)
|
4
37
|
@mod = mod
|
5
38
|
end
|
6
39
|
|
7
40
|
def paths
|
8
|
-
|
41
|
+
project_paths = full_paths(project_tfvars_dir)
|
42
|
+
stack_paths = full_paths(stack_tfvars_dir)
|
43
|
+
project_paths + stack_paths
|
44
|
+
end
|
45
|
+
memoize :paths
|
46
|
+
|
47
|
+
def full_paths(tfvars_dir)
|
48
|
+
layer_paths = full_layering.map do |layer|
|
9
49
|
[
|
10
50
|
"#{tfvars_dir}/#{layer}.tfvars",
|
11
51
|
"#{tfvars_dir}/#{layer}.rb",
|
@@ -17,74 +57,58 @@ class Terraspace::Compiler::Strategy::Tfvar
|
|
17
57
|
end
|
18
58
|
end
|
19
59
|
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
#
|
29
|
-
# namespace/env | 112233445566/dev.tfvars (provider specific)
|
30
|
-
# namespace/region/base | 112233445566/us-west-2/base.tfvars (provider specific)
|
31
|
-
# namespace/region/env | 112233445566/us-west-2/dev.tfvars (provider specific)
|
32
|
-
# provider/base | aws/base.tfvars (provider specific)
|
33
|
-
# provider/env | aws/dev.tfvars (provider specific)
|
34
|
-
# provider/region/base | aws/us-west-2/base.tfvars (provider specific)
|
35
|
-
# provider/region/env | aws/us-west-2/dev.tfvars (provider specific)
|
36
|
-
# provider/namespace/base | aws/112233445566/base.tfvars (provider specific)
|
37
|
-
# provider/namespace/env | aws/112233445566/dev.tfvars (provider specific)
|
38
|
-
# provider/namespace/region/base | aws/112233445566/us-west-2/base.tfvars (provider specific)
|
39
|
-
# provider/namespace/region/env | aws/112233445566/us-west-2/dev.tfvars (provider specific)
|
40
|
-
#
|
41
|
-
# namespace and region depends on the provider. Here an example of the mapping:
|
42
|
-
#
|
43
|
-
# | AWS | Azure | Google
|
44
|
-
# ----------|---------|--------------|-------
|
45
|
-
# namespace | account | subscription | project
|
46
|
-
# region | region | location | region
|
60
|
+
def full_layering
|
61
|
+
# layers is defined in Terraspace::Layering module
|
62
|
+
layers.inject([]) do |sum, layer|
|
63
|
+
sum += layer_levels(layer) unless layer.nil?
|
64
|
+
sum
|
65
|
+
end
|
66
|
+
end
|
67
|
+
|
68
|
+
# adds prefix and to each layer pair that has base and Terraspace.env. IE:
|
47
69
|
#
|
70
|
+
# "#{prefix}/base"
|
71
|
+
# "#{prefix}/#{Terraspace.env}"
|
48
72
|
#
|
49
|
-
def
|
50
|
-
|
73
|
+
def layer_levels(prefix=nil)
|
74
|
+
levels = ["base", Terraspace.env, @mod.instance].reject(&:blank?) # layer levels. @mod.instance can be nil
|
75
|
+
env_levels = levels.map { |l| "#{Terraspace.env}/#{l}" } # env folder also
|
76
|
+
levels = levels + env_levels
|
77
|
+
levels.map! do |i|
|
78
|
+
# base layer has prefix of '', reject with blank so it doesnt produce '//'
|
79
|
+
[prefix, i].reject(&:blank?).join('/')
|
80
|
+
end
|
81
|
+
levels.unshift(prefix) unless prefix.blank? # IE: tfvars/us-west-2.tfvars
|
82
|
+
levels
|
51
83
|
end
|
52
84
|
|
53
|
-
def
|
85
|
+
def plugins
|
54
86
|
layers = []
|
55
87
|
Terraspace::Plugin.layer_classes.each do |klass|
|
56
88
|
layer = klass.new
|
57
89
|
|
58
90
|
# region is high up because its simpler and the more common case is a single provider
|
59
|
-
layers
|
91
|
+
layers << layer.region
|
92
|
+
|
93
|
+
namespace = friendly_name(layer.namespace)
|
60
94
|
|
61
95
|
# namespace is a simple way keep different tfvars between different engineers on different accounts
|
62
|
-
layers
|
63
|
-
layers
|
96
|
+
layers << namespace
|
97
|
+
layers << "#{namespace}/#{layer.region}"
|
64
98
|
|
65
99
|
# in case using multiple providers and one region
|
66
|
-
layers
|
67
|
-
layers
|
100
|
+
layers << layer.provider
|
101
|
+
layers << "#{layer.provider}/#{layer.region}" # also in case another provider has colliding regions
|
68
102
|
|
69
103
|
# Most general layering
|
70
|
-
layers
|
71
|
-
layers
|
104
|
+
layers << "#{layer.provider}/#{namespace}"
|
105
|
+
layers << "#{layer.provider}/#{namespace}/#{layer.region}"
|
72
106
|
end
|
73
107
|
layers
|
74
108
|
end
|
75
109
|
|
76
|
-
|
77
|
-
|
78
|
-
# "#{prefix}/base"
|
79
|
-
# "#{prefix}/#{Terraspace.env}"
|
80
|
-
#
|
81
|
-
def layer_levels(prefix=nil)
|
82
|
-
levels = ["base", Terraspace.env, @mod.instance] # layer levels
|
83
|
-
env_levels = levels.map { |l| "#{Terraspace.env}/#{l}" } # env folder also
|
84
|
-
levels = levels + env_levels
|
85
|
-
levels.map do |i|
|
86
|
-
[prefix, i].compact.join('/')
|
87
|
-
end
|
110
|
+
def project_tfvars_dir
|
111
|
+
"#{Terraspace.root}/config/terraform/tfvars"
|
88
112
|
end
|
89
113
|
|
90
114
|
# seed dir takes higher precedence than the tfvars folder within the stack module. Example:
|
@@ -98,13 +122,12 @@ class Terraspace::Compiler::Strategy::Tfvar
|
|
98
122
|
# Will also consider app/modules/demo/tfvars. Though modules to be reuseable and stacks is where business logic
|
99
123
|
# should go.
|
100
124
|
#
|
101
|
-
def
|
125
|
+
def stack_tfvars_dir
|
102
126
|
seed_dir = "#{Terraspace.root}/seed/tfvars/#{@mod.build_dir(disable_instance: true)}"
|
103
127
|
mod_dir = "#{@mod.root}/tfvars"
|
104
128
|
|
105
129
|
empty = Dir.glob("#{seed_dir}/*").empty?
|
106
130
|
empty ? mod_dir : seed_dir
|
107
131
|
end
|
108
|
-
|
109
132
|
end
|
110
133
|
end
|
@@ -0,0 +1,24 @@
|
|
1
|
+
require "active_support/lazy_load_hooks"
|
2
|
+
|
3
|
+
module Terraspace
|
4
|
+
module Layering
|
5
|
+
def layers
|
6
|
+
pre_layers + main_layers + post_layers
|
7
|
+
end
|
8
|
+
|
9
|
+
def main_layers
|
10
|
+
# '' prefix for base layer
|
11
|
+
[''] + plugins
|
12
|
+
end
|
13
|
+
|
14
|
+
def pre_layers
|
15
|
+
[]
|
16
|
+
end
|
17
|
+
|
18
|
+
def post_layers
|
19
|
+
[]
|
20
|
+
end
|
21
|
+
end
|
22
|
+
end
|
23
|
+
|
24
|
+
ActiveSupport.run_load_hooks(:terraspace_layering, Terraspace::Layering)
|
data/lib/terraspace/logger.rb
CHANGED
@@ -5,7 +5,7 @@ module Terraspace
|
|
5
5
|
def initialize(*args)
|
6
6
|
super
|
7
7
|
self.formatter = Formatter.new
|
8
|
-
self.level = :info
|
8
|
+
self.level = ENV['TS_LOG_LEVEL'] || :info # note: only respected when config.logger not set in config/app.rb
|
9
9
|
end
|
10
10
|
|
11
11
|
def format_message(severity, datetime, progname, msg)
|
@@ -16,5 +16,12 @@ module Terraspace
|
|
16
16
|
end
|
17
17
|
line =~ /\n$/ ? line : "#{line}\n"
|
18
18
|
end
|
19
|
+
|
20
|
+
# Used to allow terraform output to always go to stdout
|
21
|
+
# Terraspace output goes to stderr by default
|
22
|
+
# See: terraspace/shell.rb
|
23
|
+
def stdout(msg)
|
24
|
+
puts msg
|
25
|
+
end
|
19
26
|
end
|
20
27
|
end
|
data/lib/terraspace/mod.rb
CHANGED
@@ -75,7 +75,7 @@ module Terraspace
|
|
75
75
|
#
|
76
76
|
# down - so user can delete stacks w/o needing to create an empty app/stacks/demo folder
|
77
77
|
# null - for the terraspace summary command when there are zero stacks.
|
78
|
-
# Also useful for terraspace
|
78
|
+
# Also useful for terraspace tfc list_workspaces
|
79
79
|
#
|
80
80
|
def possible_fake_root
|
81
81
|
if @options[:command] == "down"
|
@@ -111,9 +111,24 @@ module Terraspace
|
|
111
111
|
|
112
112
|
# Full path with build_dir
|
113
113
|
def cache_dir
|
114
|
-
|
114
|
+
# config.build.cache_dir is a String or object that respond_to call. IE:
|
115
|
+
# :CACHE_ROOT/:REGION/:ENV/:BUILD_DIR
|
116
|
+
# CustomBuildDir.call
|
117
|
+
# The call method should return a String pattern used for substitutions
|
118
|
+
object = Terraspace.config.build.cache_dir
|
119
|
+
pattern = if object.is_a?(String)
|
120
|
+
object
|
121
|
+
elsif object.respond_to?(:call)
|
122
|
+
object.call(self)
|
123
|
+
elsif object.public_instance_methods.include?(:call)
|
124
|
+
instance = object.new
|
125
|
+
instance.call(self)
|
126
|
+
else
|
127
|
+
raise "ERROR: config.build.cache_dir is not a String or responds to the .call method."
|
128
|
+
end
|
129
|
+
|
115
130
|
expander = Terraspace::Compiler::Expander.autodetect(self)
|
116
|
-
expander.expansion(pattern)
|
131
|
+
expander.expansion(pattern) # pattern is a String that contains placeholders for substitutions
|
117
132
|
end
|
118
133
|
memoize :cache_dir
|
119
134
|
|