cfhighlander 0.2.1 → 0.3.0.alpha.1528936037

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1,359 +0,0 @@
1
- require_relative './highlander.dsl'
2
- require 'fileutils'
3
- require 'git'
4
-
5
- LOCAL_HIGHLANDER_CACHE_LOCATION = "#{ENV['HOME']}/.highlander/components"
6
-
7
- module Highlander
8
-
9
- module Factory
10
-
11
- class Component
12
-
13
- attr_accessor :component_dir,
14
- :config,
15
- :highlander_dsl_path,
16
- :cfndsl_path,
17
- :highlander_dsl,
18
- :cfndsl_content,
19
- :mappings,
20
- :name,
21
- :version,
22
- :distribution_bucket,
23
- :distribution_prefix,
24
- :component_files,
25
- :cfndsl_ext_files,
26
- :lambda_src_files
27
-
28
- def initialize(component_name, component_dir)
29
- @name = component_name
30
- @component_dir = component_dir
31
- @mappings = {}
32
- @version = nil
33
- @distribution_bucket = nil
34
- @distribution_prefix = nil
35
- @component_files = []
36
- @cfndsl_ext_files = []
37
- @lambda_src_files = []
38
- end
39
-
40
- def load_config()
41
- @config = {} if @config.nil?
42
- Dir["#{@component_dir}/*.config.yaml"].each do |config_file|
43
- partial_config = YAML.load(File.read(config_file))
44
- unless partial_config.nil?
45
- @config.extend(partial_config)
46
- @component_files << config_file
47
- end
48
- end
49
- end
50
-
51
-
52
- def loadDepandantExt()
53
- @highlander_dsl.dependson_components.each do |requirement|
54
- requirement.component_loaded.cfndsl_ext_files.each do |file|
55
- cfndsl_ext_files << file
56
- end
57
- end
58
- end
59
-
60
- # @param [Hash] config_override
61
- def load(config_override = nil)
62
- if @component_dir.start_with? 'http'
63
- raise StandardError, 'http(s) sources not supported yet'
64
- end
65
-
66
-
67
- @highlander_dsl_path = "#{@component_dir}/#{@name}.highlander.rb"
68
- @cfndsl_path = "#{@component_dir}/#{@name}.cfndsl.rb"
69
- candidate_config_path = "#{@component_dir}/#{@name}.config.yaml"
70
- candidate_mappings_path = "#{@component_dir}/*.mappings.yaml"
71
- candidate_dynamic_mappings_path = "#{@component_dir}/#{@name}.mappings.rb"
72
-
73
- @cfndsl_ext_files += Dir["#{@component_dir}/ext/cfndsl/*.rb"]
74
- @lambda_src_files += Dir["#{@component_dir}/lambdas/**/*"].find_all {|p| not File.directory? p}
75
- @component_files += @cfndsl_ext_files
76
- @component_files += @lambda_src_files
77
-
78
- @config = {} if @config.nil?
79
-
80
- @config.extend config_override unless config_override.nil?
81
- @config['component_version'] = @version unless @version.nil?
82
- # allow override of components
83
- # config_override.each do |key, value|
84
- # @config[key] = value
85
- # end unless config_override.nil?
86
-
87
- Dir[candidate_mappings_path].each do |mapping_file|
88
- mappings = YAML.load(File.read(mapping_file))
89
- @component_files << mapping_file
90
- mappings.each do |name, map|
91
- @mappings[name] = map
92
- end unless mappings.nil?
93
- end
94
-
95
- if File.exist? candidate_dynamic_mappings_path
96
- require candidate_dynamic_mappings_path
97
- @component_files << candidate_dynamic_mappings_path
98
- end
99
-
100
- # 1st pass - parse the file
101
- @component_files << @highlander_dsl_path
102
- @highlander_dsl = eval(File.read(@highlander_dsl_path), binding)
103
-
104
- # set version if not defined
105
- @highlander_dsl.ComponentVersion(@version) unless @version.nil?
106
-
107
-
108
- # Handle name and description defaults if they are not specified
109
- # in template itself
110
- if @highlander_dsl.name.nil?
111
- @highlander_dsl.name = @name
112
- end
113
-
114
- if @highlander_dsl.description.nil?
115
- @highlander_dsl.Description("#{@highlander_dsl.name} - #{@highlander_dsl.version}")
116
- end
117
-
118
- # set (override) distribution options
119
- @highlander_dsl.DistributionBucket(@distribution_bucket) unless @distribution_bucket.nil?
120
- @highlander_dsl.DistributionPrefix(@distribution_prefix) unless @distribution_prefix.nil?
121
-
122
- if File.exist? @cfndsl_path
123
- @component_files << @cfndsl_path
124
- @cfndsl_content = File.read(@cfndsl_path)
125
- @cfndsl_content.strip!
126
- # if there is CloudFormation do [content] end extract only contents
127
- ### Regex \s is whitespace
128
- match_data = /^CloudFormation do\s(.*)end\s?$/m.match(@cfndsl_content)
129
- if not match_data.nil?
130
- @cfndsl_content = match_data[1]
131
- end
132
-
133
- else
134
- @cfndsl_content = ''
135
- end
136
-
137
- loadDepandantExt()
138
- end
139
- end
140
-
141
- class ComponentFactory
142
-
143
- attr_accessor :component_sources
144
-
145
-
146
- def initialize(component_sources = [])
147
- ## First look in local $PWD/components folder
148
- ## Then search for cached $HOME/.highlander/components
149
- ## Then search in sources given by dsl
150
- default_locations = [
151
- LOCAL_HIGHLANDER_CACHE_LOCATION,
152
- File.expand_path('components'),
153
- File.expand_path('.')
154
- ]
155
- default_locations.each do |predefined_path|
156
- component_sources.unshift(predefined_path)
157
- end
158
-
159
- @component_sources = component_sources
160
- end
161
-
162
- def findComponentDefault(component_name, component_version)
163
- default_lookup_url = 'https://github.com/theonestack'
164
- default_lookup_url = ENV['HIGHLANDER_DEFAULT_COMPONENT_GIT_LOOKUP'] if ENV.key? 'HIGHLANDER_DEFAULT_COMPONENT_GIT_LOOKUP'
165
-
166
- git_url = "#{default_lookup_url}/hl-component-#{component_name}"
167
-
168
- if component_version.nil? or component_version.empty? or component_version == 'latest'
169
- branch = 'master'
170
- else
171
- branch = component_version
172
- end
173
- local_path = "#{LOCAL_HIGHLANDER_CACHE_LOCATION}/#{component_name}/#{component_version}"
174
- return findComponentGit(local_path, component_name, component_version, git_url, branch)
175
-
176
- end
177
-
178
- def findComponentGit(local_path, component_name, component_version, git_url, branch)
179
- begin
180
- local_path = "#{local_path}/" unless local_path.end_with? '/'
181
- # if this is snapshot, clean local cache
182
- if branch.end_with? '.snapshot'
183
- branch = branch.gsub('.snapshot', '')
184
- FileUtils.rmtree local_path if File.exist? local_path and File.directory? local_path
185
- end
186
-
187
- # if local cache exists, return from cache
188
- if not Dir.glob("#{local_path}*.highlander.rb").empty?
189
- # if cache exists, just return from cache
190
- component_name = Dir.glob("#{local_path}*.highlander.rb")[0].gsub(local_path, '').gsub('.highlander.rb','')
191
- return component_name, local_path
192
- end
193
-
194
- # shallow clone
195
- puts "Trying to load #{component_name}/#{component_version} from #{git_url}##{branch} ... "
196
- clone_opts = { depth: 1 }
197
- clone_opts[:branch] = branch if not (branch.nil? or branch.empty?)
198
- Git.clone git_url, local_path, clone_opts
199
- puts "\t .. cached in #{local_path}\n"
200
- # return from cache once it's cloned
201
- return findComponentGit(local_path, component_name, component_version, git_url, branch)
202
- rescue Exception => e
203
- STDERR.puts "Failed to resolve component #{component_name}@#{component_version} from #{git_url}"
204
- STDERR.puts e
205
- return nil
206
- end
207
- end
208
-
209
- def findComponentS3(s3_location, component_name, component_version)
210
- parts = s3_location.split('/')
211
- bucket = parts[2]
212
- prefix = parts[3]
213
- s3_key = "#{prefix}/#{component_name}/#{component_version}/#{component_name}.highlander.rb"
214
- s3_prefix = "#{prefix}/#{component_name}/#{component_version}/"
215
- local_destination = "#{LOCAL_HIGHLANDER_CACHE_LOCATION}/#{component_name}/#{component_version}"
216
- begin
217
- s3 = Aws::S3::Client.new({ region: s3_bucket_region(bucket) })
218
- FileUtils.mkdir_p local_destination unless Dir.exist? local_destination
219
-
220
- hl_content = s3.get_object({ bucket: bucket,
221
- key: s3_key,
222
- response_target: "#{local_destination}/#{component_name}.highlander.rb"
223
- })
224
- # if code execution got so far we consider file exists and download it locally
225
- component_files = s3.list_objects_v2({ bucket: bucket, prefix: s3_prefix })
226
- component_files.contents.each {|s3_object|
227
- file_name = s3_object.key.gsub(s3_prefix, '')
228
- destination_file = "#{local_destination}/#{file_name}"
229
- destination_dir = File.dirname(destination_file)
230
- print "Caching #{file_name} of #{component_name}@#{component_version} in #{destination_dir} ... "
231
-
232
- FileUtils.mkpath(destination_dir) unless File.exists?(destination_dir)
233
- s3.get_object({ bucket: bucket, key: s3_object.key, response_target: destination_file })
234
- print " [OK] \n"
235
- }
236
- return local_destination
237
- rescue => e
238
- # this handles both nonexisting key and bucket
239
- puts("#{component_name} not found in s3://#{bucket}/#{prefix}")
240
- STDERR.puts(e.to_s) unless e.message.include? 'does not exist'
241
- return nil
242
- end
243
- end
244
-
245
- def findComponentGitTemplate(component_name, component_version)
246
- if component_name.include? '#'
247
- parts = component_name.split('#')
248
- component_name = parts[0]
249
- component_version = parts[1]
250
- end
251
-
252
- # avoid any nres
253
- component_version = '' if component_version.nil?
254
-
255
- # if empty or latest branch is empty
256
- if component_version.empty? or component_version == 'latest' or component_version == 'latest.snapshot'
257
- branch = ''
258
- else
259
- # otherwise component version is actual branch
260
- branch = component_version
261
- end
262
-
263
-
264
- git_url = nil
265
- if component_name.start_with? 'git:'
266
- git_url = component_name.gsub('git:', '')
267
- elsif component_name.start_with? 'github:'
268
- git_url = "https://github.com/#{component_name.gsub('github:', '')}"
269
- elsif component_name.start_with? 'github.com:'
270
- git_url = "https://github.com/#{component_name.gsub('github.com:', '')}"
271
- end
272
-
273
- local_path = "#{LOCAL_HIGHLANDER_CACHE_LOCATION}/#{component_name}/#{component_version}"
274
-
275
- if not git_url.nil?
276
- component_name, location = findComponentGit(local_path, component_name, component_version, git_url, branch)
277
- if location.nil?
278
- raise "Could not resolve component #{component_name}@#{component_version}"
279
- else
280
- return component_name, location
281
- end
282
- end
283
-
284
- return nil
285
- end
286
-
287
- # Find component and given list of sources
288
- # @return [Highlander::Factory::Component]
289
- def findComponent(component_name, component_version = nil)
290
-
291
- component_version_s = component_version.nil? ? 'latest' : component_version
292
- component_version = nil if component_version == 'latest'
293
-
294
- if component_name.include? '@' and (not component_name.start_with? 'git')
295
- parts = component_name.split('@')
296
- component_name = parts[0]
297
- component_version = parts[1]
298
- end
299
-
300
- # if component specified as git location
301
- new_name, candidate_git = findComponentGitTemplate(component_name, component_version_s)
302
- return buildComponent(new_name, candidate_git) unless candidate_git.nil?
303
-
304
- # if not git but has .snapshot lookup in default
305
- if (not component_version.nil?) and component_version.end_with? '.snapshot'
306
- new_name, default_candidate = findComponentDefault(component_name, component_version_s)
307
- return buildComponent(new_name, default_candidate) unless default_candidate.nil?
308
- end
309
-
310
- # try in all of the component source
311
- @component_sources.each do |source|
312
- component_full_name = "#{component_name}@#{component_version.nil? ? 'latest' : component_version}"
313
- # TODO handle http(s) sources and their download to local
314
- if source.start_with?('http')
315
- raise StandardError, 'http(s) sources not supported yet'
316
- elsif source.start_with?('s3://')
317
- # s3 candidate
318
-
319
- s3_candidate = findComponentS3(source, component_name, component_version_s)
320
- if not s3_candidate.nil?
321
- # at this point all component files are download to local file system and consumed from there
322
- return buildComponent(component_name, s3_candidate)
323
- end
324
-
325
- else
326
- # file system candidate
327
- candidate = "#{source}/#{component_name}"
328
- candidate = "#{candidate}/#{component_version}" unless component_version.nil?
329
- candidate_hl_path = "#{candidate}/#{component_name}.highlander.rb"
330
- candidate2_hl_path = "#{source}/#{component_name}.highlander.rb"
331
- puts "Trying to load #{component_full_name} from #{candidate} ... "
332
- if File.exist?(candidate_hl_path)
333
- return buildComponent(component_name, candidate)
334
- end
335
- puts "Trying to load #{component_full_name} from #{source} ... "
336
- if File.exist?(candidate2_hl_path)
337
- return buildComponent(component_name, source)
338
- end unless component_version_s != 'latest'
339
- end
340
- end
341
-
342
- # try default component source on github
343
- component_name, default_candidate = findComponentDefault(component_name, component_version_s)
344
- return buildComponent(component_name, default_candidate) unless default_candidate.nil?
345
-
346
- raise StandardError, "highlander template #{component_name}@#{component_version_s} not located" +
347
- " in sources #{@component_sources}"
348
- end
349
-
350
- def buildComponent(component_name, component_dir)
351
- component = Component.new(component_name, component_dir)
352
- component.load_config
353
- return component
354
- end
355
-
356
- end
357
- end
358
-
359
- end