Class: Hako::EnvExpander

Inherits:
Object
  • Object
show all
Defined in:
lib/hako/env_expander.rb

Defined Under Namespace

Classes: ExpansionError, Literal, Variable

Instance Method Summary collapse

Constructor Details

#initialize(providers) ⇒ EnvExpander



17
18
19
# File 'lib/hako/env_expander.rb', line 17

def initialize(providers)
  @providers = providers
end

Instance Method Details

#expand(env) ⇒ Hash<String, String>



23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
# File 'lib/hako/env_expander.rb', line 23

def expand(env)
  parsed_env = parse_env(env)
  variables = Set.new
  parsed_env.each_value do |tokens|
    tokens.each do |t|
      if t.is_a?(Variable)
        variables << t.name
      end
    end
  end

  values = {}
  @providers.each do |provider|
    if variables.empty?
      break
    end

    provider.ask(variables.to_a).each do |var, val|
      values[var] = val
      variables.delete(var)
    end
  end
  unless variables.empty?
    raise ExpansionError.new("Could not resolve embedded variables from $providers=#{@providers}: #{variables.to_a}")
  end

  expanded_env = {}
  parsed_env.each do |key, tokens|
    expanded_env[key] = tokens.map { |t| expand_value(values, t) }.join('')
  end
  expanded_env
end

#expand_value(values, token) ⇒ Object (private)



132
133
134
135
136
137
138
139
140
141
# File 'lib/hako/env_expander.rb', line 132

def expand_value(values, token)
  case token
  when Literal
    token.literal
  when Variable
    values.fetch(token.name)
  else
    raise ExpansionError.new("Unknown token type: #{token.class}")
  end
end

#parse(value) ⇒ Array (private)



108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
# File 'lib/hako/env_expander.rb', line 108

def parse(value)
  s = StringScanner.new(value)
  tokens = []
  pos = 0
  while s.scan_until(/#\{(.*?)\}/)
    pre = s.string.byteslice(pos...(s.pos - s.matched.size))
    var = s[1]
    unless pre.empty?
      tokens << Literal.new(pre)
    end
    if var.empty?
      raise ExpansionError.new('Empty interpolation is not allowed')
    else
      tokens << Variable.new(var)
    end

    pos = s.pos
  end
  unless s.rest.empty?
    tokens << Literal.new(s.rest)
  end
  tokens
end

#parse_env(env) ⇒ Hash<String, Array<Literal, Variable>> (private)



94
95
96
97
98
99
100
101
102
103
104
# File 'lib/hako/env_expander.rb', line 94

def parse_env(env)
  parsed_env = {}
  env.each do |key, val|
    unless val.is_a?(String)
      raise ExpansionError.new("#{key} must be a String but got #{val.class}: #{val.inspect}")
    end

    parsed_env[key] = parse(val)
  end
  parsed_env
end

#validate!(env) ⇒ Boolean



58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
# File 'lib/hako/env_expander.rb', line 58

def validate!(env)
  parsed_env = parse_env(env)
  variables = Set.new
  parsed_env.each_value do |tokens|
    tokens.each do |t|
      if t.is_a?(Variable)
        variables << t.name
      end
    end
  end

  @providers.each do |provider|
    if variables.empty?
      break
    end

    if provider.can_ask_keys?
      provider.ask_keys(variables.to_a).each do |var|
        variables.delete(var)
      end
    else
      Hako.logger.warn("EnvProvider#validate! is skipped because #{provider.class} doesn't support ask_keys method")
      return false
    end
  end
  unless variables.empty?
    raise ExpansionError.new("Could not find embedded variables from $providers=#{@providers}: #{variables.to_a}")
  end

  true
end