class Fauxhai::Mocker

Constants

PLATFORM_LIST_MESSAGE

A message about where to find a list of platforms

RAW_BASE

The base URL for the GitHub project (raw)

Public Class Methods

new(options = {}) { |data| ... } click to toggle source

Create a new Ohai Mock with fauxhai.

@param [Hash] options

the options for the mocker

@option options [String] :platform

the platform to mock

@option options [String] :version

the version of the platform to mock

@option options [String] :path

the path to a local JSON file

@option options [Bool] :github_fetching

whether to try loading from Github
# File lib/fauxhai/mocker.rb, line 25
def initialize(options = {}, &override_attributes)
  @options = { github_fetching: true }.merge(options)

  yield(data) if block_given?
end

Public Instance Methods

data() click to toggle source
# File lib/fauxhai/mocker.rb, line 31
def data
  @fauxhai_data ||= lambda do
    # If a path option was specified, use it
    if @options[:path]
      filepath = File.expand_path(@options[:path])

      unless File.exist?(filepath)
        raise Fauxhai::Exception::InvalidPlatform.new("You specified a path to a JSON file on the local system that does not exist: '#{filepath}'")
      end
    else
      filepath = File.join(platform_path, "#{version}.json")
    end

    if File.exist?(filepath)
      parse_and_validate(File.read(filepath))
    elsif @options[:github_fetching]
      # Try loading from github (in case someone submitted a PR with a new file, but we haven't
      # yet updated the gem version). Cache the response locally so it's faster next time.
      begin
        response = open("#{RAW_BASE}/lib/fauxhai/platforms/#{platform}/#{version}.json")
      rescue OpenURI::HTTPError
        raise Fauxhai::Exception::InvalidPlatform.new("Could not find platform '#{platform}/#{version}' on the local disk and an HTTP error was encountered when fetching from Github. #{PLATFORM_LIST_MESSAGE}")
      end

      if response.status.first.to_i == 200
        response_body = response.read
        path = Pathname.new(filepath)
        FileUtils.mkdir_p(path.dirname)

        begin
          File.open(filepath, 'w') { |f| f.write(response_body) }
        rescue Errno::EACCES # a pretty common problem in CI systems
          puts "Fetched '#{platform}/#{version}' from GitHub, but could not write to the local path: #{filepath}. Fix the local file permissions to avoid downloading this file every run."
        end
        return parse_and_validate(response_body)
      else
        raise Fauxhai::Exception::InvalidPlatform.new("Could not find platform '#{platform}/#{version}' on the local disk and an Github fetching returned http error code #{response.status.first.to_i}! #{PLATFORM_LIST_MESSAGE}")
      end
    else
      raise Fauxhai::Exception::InvalidPlatform.new("Could not find platform '#{platform}/#{version}' on the local disk and Github fetching is disabled! #{PLATFORM_LIST_MESSAGE}")
    end
  end.call
end

Private Instance Methods

parse_and_validate(unparsed_data) click to toggle source

As major releases of Ohai ship it's difficult and sometimes impossible to regenerate all fauxhai data. This allows us to deprecate old releases and eventually remove them while giving end users ample warning.

# File lib/fauxhai/mocker.rb, line 80
def parse_and_validate(unparsed_data)
  parsed_data = JSON.parse(unparsed_data)
  if parsed_data['deprecated']
    STDERR.puts "WARNING: Fauxhai platform data for #{parsed_data['platform']} #{parsed_data['platform_version']} is deprecated and will be removed in the 7.0 release 3/2019. #{PLATFORM_LIST_MESSAGE}"
  end
  parsed_data
end
platform() click to toggle source
# File lib/fauxhai/mocker.rb, line 88
def platform
  @options[:platform] ||= begin
                            STDERR.puts "WARNING: you must specify a 'platform' and optionally a 'version' for your ChefSpec Runner and/or Fauxhai constructor, in the future omitting the platform will become a hard error. #{PLATFORM_LIST_MESSAGE}"
                            'chefspec'
                          end
end
platform_path() click to toggle source
# File lib/fauxhai/mocker.rb, line 95
def platform_path
  File.join(Fauxhai.root, 'lib', 'fauxhai', 'platforms', platform)
end
version() click to toggle source
# File lib/fauxhai/mocker.rb, line 99
def version
  @version ||= begin
    if File.exist?("#{platform_path}/#{@options[:version]}.json")
      # Whole version, use it as-is.
      @options[:version]
    else
      # Check if it's a prefix of an existing version.
      versions = Dir["#{platform_path}/*.json"].map {|path| File.basename(path, '.json') }
      unless @options[:version].to_s == ''
        # If the provided version is nil or '', that means take anything,
        # otherwise run the prefix match with an extra \D to avoid the
        # case where "7.1" matches "7.10.0".
        prefix_re = /^#{Regexp.escape(@options[:version])}\D/
        versions.select! {|ver| ver =~ prefix_re }
      end

      if versions.empty?
        # No versions available, either an unknown platform or nothing matched
        # the prefix check. Pass through the option as given so we can try
        # github fetching.
        @options[:version]
      else
        # Take the highest version available, trying to use rules that should
        # probably mostly work on all OSes. Famous last words. The idea of
        # the regex is to split on any punctuation (the common case) and
        # also any single letter with digit on either side (2012r2). This
        # leaves any long runs of letters intact (4.2-RELEASE). Then convert
        # any run of digits to an integer to get version-ish comparison.
        # This is basically a more flexible version of Gem::Version.
        versions.max_by do |ver|
          ver.split(/[^a-z0-9]|(?<=\d)[a-z](?=\d)/i).map do |part|
            if part =~ /^\d+$/
              part.to_i
            else
              part
            end
          end
        end
      end
    end
  end
end