class Cfhighlander::Factory::TemplateFinder

Public Class Methods

new(component_sources = [], parent_path = nil) click to toggle source
# File lib/cfhighlander.factory.templatefinder.rb, line 11
def initialize(component_sources = [], parent_path = nil)
  ## First look in parent path and it's components folder
  ## Then look in local $PWD/components folder
  ## Then search for cached $HOME/.highlander/components
  ## Then search in sources given by dsl
  default_locations = [
      LOCAL_CFHIGHLANDER_CACHE_LOCATION,
      File.expand_path('components'),
      File.expand_path('.'),
  ]

  default_locations << ENV['CFHIGHLANDER_WORKDIR'] if ENV.key? 'CFHIGHLANDER_WORKDIR'
  default_locations.each do |predefined_path|
    component_sources.unshift(predefined_path)
  end
  component_sources.unshift "#{parent_path}/components" if parent_path
  component_sources.unshift parent_path if parent_path

  @component_sources = component_sources
end

Public Instance Methods

build_meta(template_name, template_version, template_location) click to toggle source
# File lib/cfhighlander.factory.templatefinder.rb, line 242
def build_meta(template_name, template_version, template_location)
  template_location = template_location[0..-2] if template_location.end_with? File::SEPARATOR
  return Cfhighlander::Model::TemplateMetadata.new(
      template_name: template_name,
      template_version: template_version,
      template_location: template_location)
end
findTemplate(template_name, template_version) click to toggle source
# File lib/cfhighlander.factory.templatefinder.rb, line 168
def findTemplate(template_name, template_version)
  template_version_s = template_version.nil? ? 'latest' : template_version
  template_version = nil if template_version == 'latest'
  is_git_template = template_name.start_with? 'git'

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

  if template_name.include? '#' and (is_git_template)
    parts = template_name.split('#')
    template_name = parts[0]
    template_version = parts[1]
    template_version_s = template_version
  end

  # if component specified as git location
  if is_git_template
    new_template_name, new_version, candidate_git = tryFindTemplateGit(template_name, template_version_s)
    return build_meta(new_template_name, new_version, candidate_git) unless candidate_git.nil?
  end

  # if not git but has .snapshot lookup in default, it is allowed to reference default
  # snapshots
  if (not template_version.nil?) and template_version.end_with? '.snapshot'
    new_template_name, snapshot_candidate_location = findTemplateDefault(template_name, template_version_s)
    return build_meta(new_template_name, template_version, snapshot_candidate_location) unless snapshot_candidate_location.nil?
  end

  # try in all of the component sources
  @component_sources.each do |source|
    template_full_name = "#{template_name}@#{template_version.nil? ? 'latest' : template_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 = findTemplateS3(source, template_name, template_version_s)
      # at this point all component files are download to local file system and consumed from there
      return build_meta(template_name, template_version_s, s3_candidate) unless s3_candidate.nil?

    else
      # file system candidate
      candidate = "#{source}/#{template_name}"
      candidate = "#{candidate}/#{template_version}" unless template_version.nil?
      candidate_hl_path = "#{candidate}/#{template_name}.highlander.rb"
      candidate_cfhl_path = "#{candidate}/#{template_name}.cfhighlander.rb"
      candidate2_hl_path = "#{source}/#{template_name}.highlander.rb"
      candidate2_cfhl_path = "#{source}/#{template_name}.cfhighlander.rb"
      puts "TRACE: Trying to load #{template_full_name} from #{candidate} ... "
      if (File.exist?(candidate_hl_path) or File.exist?(candidate_cfhl_path))
        return build_meta(template_name, template_version_s, candidate)
      end

      puts "TRACE: Trying to load #{template_full_name} from #{source} ... "
      # if component version is latest it is allowed to search in path
      # with no version component in it
      if (File.exist?(candidate2_hl_path) or File.exist?(candidate2_cfhl_path))
        return build_meta(template_name, 'latest', source)
      end unless template_version_s != 'latest'
    end
  end

  # try default component source on github
  template_name, default_candidate = findTemplateDefault(template_name, template_version_s)
  return build_meta(template_name, template_version_s, default_candidate) unless default_candidate.nil?

  return nil
end
findTemplateDefault(template_name, component_version) click to toggle source
# File lib/cfhighlander.factory.templatefinder.rb, line 32
def findTemplateDefault(template_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'
  default_lookup_url = ENV['CFHIGHLANDER_DEFAULT_COMPONENT_GIT_LOOKUP'] if ENV.key? 'CFHIGHLANDER_DEFAULT_COMPONENT_GIT_LOOKUP'

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

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

end
findTemplateGit(cache_path, component_name, component_version, git_url, branch) click to toggle source
# File lib/cfhighlander.factory.templatefinder.rb, line 49
def findTemplateGit(cache_path, component_name, component_version, git_url, branch)
  begin
    cache_path = "#{cache_path}/" unless cache_path.end_with? '/'
    # if this is snapshot, clean local cache
    if branch.end_with? '.snapshot'
      branch = branch.gsub('.snapshot', '')
      FileUtils.rmtree cache_path if File.exist? cache_path and File.directory? cache_path
    end

    # if local cache exists, return from cache
    if not Dir.glob("#{cache_path}*.highlander.rb").empty?
      # if cache exists, just return from cache
      component_name = Dir.glob("#{cache_path}*.highlander.rb")[0].gsub(cache_path, '').gsub('.highlander.rb', '')
      STDERR.puts("DEPRECATED: #{component_name}: Use *.cfhighlander.rb template file name pattern")
      return component_name, cache_path
    end

    if not Dir.glob("#{cache_path}*.cfhighlander.rb").empty?
      # if cache exists, just return from cache
      component_name = Dir.glob("#{cache_path}*.cfhighlander.rb")[0].gsub(cache_path, '').gsub('.cfhighlander.rb', '')
      return component_name, cache_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, cache_path, clone_opts
    puts "\t .. cached in #{cache_path}\n"
    # return from cache once it's cloned
    return findTemplateGit(cache_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
findTemplateS3(s3_location, component_name, component_version, use_legacy_extension = true) click to toggle source
# File lib/cfhighlander.factory.templatefinder.rb, line 87
def findTemplateS3(s3_location, component_name, component_version, use_legacy_extension = true)
  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_CFHIGHLANDER_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}.#{use_legacy_extension ? 'highlander' : 'cfhighlander'}.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"
    }
    if use_legacy_extension
      STDERR.puts "DEPRECATED: s3 load #{component_name} with *.highlander.rb template file name pattern"
    end
    return local_destination
  rescue => e
    # this handles both nonexisting key and bucket
    if use_legacy_extension
      return findTemplateS3(s3_location, component_name, component_version, false)
    end
    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
tryFindTemplateGit(template_location, template_version) click to toggle source

will try and locate template based on git template location if template location is not git repo, returns nil

# File lib/cfhighlander.factory.templatefinder.rb, line 131
def tryFindTemplateGit(template_location, template_version)

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

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


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


  if not git_url.nil?
    local_path = "#{LOCAL_CFHIGHLANDER_CACHE_LOCATION}/#{template_location.gsub(':', '_').gsub(/\/+/, '/')}/#{template_version}"
    template_name, location = findTemplateGit(local_path, template_location, template_version, git_url, branch)
    if location.nil?
      raise "Could not resolve component #{template_location}@#{template_version}"
    else
      return template_name, template_version, location
    end
  end

  return nil
end