Class: Highlander::Factory::ComponentFactory

Inherits:
Object
  • Object
show all
Defined in:
lib/highlander.factory.rb

Instance Attribute Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(component_sources = []) ⇒ ComponentFactory

Returns a new instance of ComponentFactory.



146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
# File 'lib/highlander.factory.rb', line 146

def initialize(component_sources = [])
  ## First look in local $PWD/components folder
  ## Then search for cached $HOME/.highlander/components
  ## Then search in sources given by dsl
  default_locations = [
      LOCAL_HIGHLANDER_CACHE_LOCATION,
      File.expand_path('components'),
      File.expand_path('.')
  ]
  default_locations.each do |predefined_path|
    component_sources.unshift(predefined_path)
  end

  @component_sources = component_sources
end

Instance Attribute Details

#component_sources ⇒ Object

Returns the value of attribute component_sources.



143
144
145
# File 'lib/highlander.factory.rb', line 143

def component_sources
  @component_sources
end

Instance Method Details

#buildComponent(component_name, component_dir) ⇒ Object



350
351
352
353
354
# File 'lib/highlander.factory.rb', line 350

def buildComponent(component_name, component_dir)
  component = Component.new(component_name, component_dir)
  component.load_config
  return component
end

#findComponent(component_name, component_version = nil) ⇒ Highlander::Factory::Component

Find component and given list of sources

Returns:

Raises:

  • (StandardError)


289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
# File 'lib/highlander.factory.rb', line 289

def findComponent(component_name, component_version = nil)

  component_version_s = component_version.nil? ? 'latest' : component_version
  component_version = nil if component_version == 'latest'

  if component_name.include? '@' and (not component_name.start_with? 'git')
    parts = component_name.split('@')
    component_name = parts[0]
    component_version = parts[1]
  end

  # if component specified as git location
  new_name, candidate_git = findComponentGitTemplate(component_name, component_version_s)
  return buildComponent(new_name, candidate_git) unless candidate_git.nil?

  # if not git but has .snapshot lookup in default
  if (not component_version.nil?) and component_version.end_with? '.snapshot'
    new_name, default_candidate = findComponentDefault(component_name, component_version_s)
    return buildComponent(new_name, default_candidate) unless default_candidate.nil?
  end

  # try in all of the component source
  @component_sources.each do |source|
    component_full_name = "#{component_name}@#{component_version.nil? ? 'latest' : component_version}"
    # TODO handle http(s) sources and their download to local
    if source.start_with?('http')
      raise StandardError, 'http(s) sources not supported yet'
    elsif source.start_with?('s3://')
      # s3 candidate

      s3_candidate = findComponentS3(source, component_name, component_version_s)
      if not s3_candidate.nil?
        # at this point all component files are download to local file system and consumed from there
        return buildComponent(component_name, s3_candidate)
      end

    else
      # file system candidate
      candidate = "#{source}/#{component_name}"
      candidate = "#{candidate}/#{component_version}" unless component_version.nil?
      candidate_hl_path = "#{candidate}/#{component_name}.highlander.rb"
      candidate2_hl_path = "#{source}/#{component_name}.highlander.rb"
      puts "Trying to load #{component_full_name} from #{candidate} ... "
      if File.exist?(candidate_hl_path)
        return buildComponent(component_name, candidate)
      end
      puts "Trying to load #{component_full_name} from #{source} ... "
      if File.exist?(candidate2_hl_path)
        return buildComponent(component_name, source)
      end unless component_version_s != 'latest'
    end
  end

  # try default component source on github
  component_name, default_candidate = findComponentDefault(component_name, component_version_s)
  return buildComponent(component_name, default_candidate) unless default_candidate.nil?

  raise StandardError, "highlander template #{component_name}@#{component_version_s} not located" +
      " in sources #{@component_sources}"
end

#findComponentDefault(component_name, component_version) ⇒ Object



162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
# File 'lib/highlander.factory.rb', line 162

def findComponentDefault(component_name, component_version)
  default_lookup_url = 'https://github.com/theonestack'
  default_lookup_url = ENV['HIGHLANDER_DEFAULT_COMPONENT_GIT_LOOKUP'] if ENV.key? 'HIGHLANDER_DEFAULT_COMPONENT_GIT_LOOKUP'

  git_url = "#{default_lookup_url}/hl-component-#{component_name}"

  if component_version.nil? or component_version.empty? or component_version == 'latest'
    branch = 'master'
  else
    branch = component_version
  end
  local_path = "#{LOCAL_HIGHLANDER_CACHE_LOCATION}/#{component_name}/#{component_version}"
  return findComponentGit(local_path, component_name, component_version, git_url, branch)

end

#findComponentGit(local_path, component_name, component_version, git_url, branch) ⇒ Object



178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
# File 'lib/highlander.factory.rb', line 178

def findComponentGit(local_path, component_name, component_version, git_url, branch)
  begin
    local_path = "#{local_path}/" unless local_path.end_with? '/'
    # if this is snapshot, clean local cache
    if branch.end_with? '.snapshot'
      branch = branch.gsub('.snapshot', '')
      FileUtils.rmtree local_path if File.exist? local_path and File.directory? local_path
    end

    # if local cache exists, return from cache
    if not Dir.glob("#{local_path}*.highlander.rb").empty?
      # if cache exists, just return from cache
      component_name = Dir.glob("#{local_path}*.highlander.rb")[0].gsub(local_path, '').gsub('.highlander.rb','')
      return component_name, local_path
    end

    # shallow clone
    puts "Trying to load #{component_name}/#{component_version} from #{git_url}##{branch} ... "
    clone_opts = { depth: 1 }
    clone_opts[:branch] = branch if not (branch.nil? or branch.empty?)
    Git.clone git_url, local_path, clone_opts
    puts "\t .. cached in #{local_path}\n"
    # return from cache once it's cloned
    return findComponentGit(local_path, component_name, component_version, git_url, branch)
  rescue Exception => e
    STDERR.puts "Failed to resolve component #{component_name}@#{component_version} from #{git_url}"
    STDERR.puts e
    return nil
  end
end

#findComponentGitTemplate(component_name, component_version) ⇒ Object



245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
# File 'lib/highlander.factory.rb', line 245

def findComponentGitTemplate(component_name, component_version)
  if component_name.include? '#'
    parts = component_name.split('#')
    component_name = parts[0]
    component_version = parts[1]
  end

  # avoid any nres
  component_version = '' if component_version.nil?

  # if empty or latest branch is empty
  if component_version.empty? or component_version == 'latest' or component_version == 'latest.snapshot'
    branch = ''
  else
    # otherwise component version is actual branch
    branch = component_version
  end


  git_url = nil
  if component_name.start_with? 'git:'
    git_url = component_name.gsub('git:', '')
  elsif component_name.start_with? 'github:'
    git_url = "https://github.com/#{component_name.gsub('github:', '')}"
  elsif component_name.start_with? 'github.com:'
    git_url = "https://github.com/#{component_name.gsub('github.com:', '')}"
  end

  local_path = "#{LOCAL_HIGHLANDER_CACHE_LOCATION}/#{component_name}/#{component_version}"

  if not git_url.nil?
    component_name, location = findComponentGit(local_path, component_name, component_version, git_url, branch)
    if location.nil?
      raise "Could not resolve component #{component_name}@#{component_version}"
    else
      return component_name, location
    end
  end

  return nil
end

#findComponentS3(s3_location, component_name, component_version) ⇒ Object



209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
# File 'lib/highlander.factory.rb', line 209

def findComponentS3(s3_location, component_name, component_version)
  parts = s3_location.split('/')
  bucket = parts[2]
  prefix = parts[3]
  s3_key = "#{prefix}/#{component_name}/#{component_version}/#{component_name}.highlander.rb"
  s3_prefix = "#{prefix}/#{component_name}/#{component_version}/"
  local_destination = "#{LOCAL_HIGHLANDER_CACHE_LOCATION}/#{component_name}/#{component_version}"
  begin
    s3 = Aws::S3::Client.new({ region: s3_bucket_region(bucket) })
    FileUtils.mkdir_p local_destination unless Dir.exist? local_destination

    hl_content = s3.get_object({ bucket: bucket,
        key: s3_key,
        response_target: "#{local_destination}/#{component_name}.highlander.rb"
    })
    # if code execution got so far we consider file exists and download it locally
    component_files = s3.list_objects_v2({ bucket: bucket, prefix: s3_prefix })
    component_files.contents.each {|s3_object|
      file_name = s3_object.key.gsub(s3_prefix, '')
      destination_file = "#{local_destination}/#{file_name}"
      destination_dir = File.dirname(destination_file)
      print "Caching #{file_name} of #{component_name}@#{component_version} in #{destination_dir} ... "

      FileUtils.mkpath(destination_dir) unless File.exists?(destination_dir)
      s3.get_object({ bucket: bucket, key: s3_object.key, response_target: destination_file })
      print " [OK] \n"
    }
    return local_destination
  rescue => e
    # this handles both nonexisting key and bucket
    puts("#{component_name} not found in s3://#{bucket}/#{prefix}")
    STDERR.puts(e.to_s) unless e.message.include? 'does not exist'
    return nil
  end
end