Class: Inspec::CachedFetcher

Inherits:
Object
  • Object
show all
Extended by:
Forwardable
Defined in:
lib/inspec/cached_fetcher.rb

Instance Attribute Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(target, cache, opts = {}) ⇒ CachedFetcher

Returns a new instance of CachedFetcher.



9
10
11
12
13
14
15
16
17
18
# File 'lib/inspec/cached_fetcher.rb', line 9

def initialize(target, cache, opts = {})
  @target = target
  @fetcher = Inspec::Fetcher::Registry.resolve(target, opts)

  if @fetcher.nil?
    raise("Could not fetch inspec profile in #{target.inspect}.")
  end

  @cache = cache
end

Instance Attribute Details

#cacheObject (readonly)

Returns the value of attribute cache.



8
9
10
# File 'lib/inspec/cached_fetcher.rb', line 8

def cache
  @cache
end

#fetcherObject (readonly)

Returns the value of attribute fetcher.



8
9
10
# File 'lib/inspec/cached_fetcher.rb', line 8

def fetcher
  @fetcher
end

#targetObject (readonly)

Returns the value of attribute target.



8
9
10
# File 'lib/inspec/cached_fetcher.rb', line 8

def target
  @target
end

Instance Method Details

#assert_cache_sanity!Object



87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
# File 'lib/inspec/cached_fetcher.rb', line 87

def assert_cache_sanity!
  # do not check cache sanity if the target is a gem or a resource pack
  # which are known by a special prefix on their cache key or by having the :gem key
  return if target.respond_to?(:key?) && target.key?(:gem)
  return unless target.respond_to?(:key?) && target.key?(:sha256)

  exception_message = <<~EOF
    The remote source #{fetcher} no longer has the requested content:

    Request Content Hash: #{target[:sha256]}
    Actual Content Hash: #{fetcher.resolved_source[:sha256]}

    For URL, supermarket, compliance, and other sources that do not
    provide versioned artifacts, this likely means that the remote source
    has changed since your lockfile was generated.
  EOF
  raise exception_message if fetcher.resolved_source[:sha256] != target[:sha256]
end

#cache_keyObject



29
30
31
32
33
34
35
36
37
38
39
# File 'lib/inspec/cached_fetcher.rb', line 29

def cache_key
  k = if target.is_a?(Hash)
        target[:sha256] || target[:ref]
      end

  if k.nil?
    fetcher.cache_key
  else
    k
  end
end

#fetchObject



41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
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
# File 'lib/inspec/cached_fetcher.rb', line 41

def fetch
  if cache.exists?(cache_key) && cache.locked?(cache_key)
    Inspec::Log.debug "Waiting for lock to be released on the cache dir ...."
    counter = 0
    until cache.locked?(cache_key) == false
      if (counter += 1) > 300
        Inspec::Log.warn "Giving up waiting on cache lock at #{cache_key}"
        exit 1
      end
      sleep 0.1
    end
    fetch
  elsif cache.exists?(cache_key) && !cache.locked?(cache_key)
    Inspec::Log.debug "Using cached dependency for #{target}"
    cache_value = cache.prefered_entry_for(cache_key)
    if cache_value
      [cache_value, false]
    else
      Inspec::Log.debug "Dependency does not exist in the cache for target #{target}"
      cache_key_name = cache_key
      if cache_key_name.start_with?("gem:")
        # When cache for gem - meaning gemspec exists but gem does not exists then clearing up gemspec is required
        # This logic enables the gem fetcher logic to work step by step again
        Inspec::Log.debug "Clearing cached gemspec to fix dependency issue and enable fresh download."
        FileUtils.rm_rf(cache.gemspec_path_for(cache_key))
      end
    end
  else
    begin
      Inspec::Log.debug "Dependency does not exist in the cache #{target}"
      cache.lock(cache.base_path_for(fetcher.cache_key)) if fetcher.requires_locking?
      fetcher.fetch(cache.base_path_for(fetcher.cache_key))
    rescue SystemExit => e
      exit_code = e.status || 1
      Inspec::Log.error "Error while creating cache for dependency ... #{e.message}"
      # TODO: in the case of gem profile/resource pack dependency installs gone awry, this is the wrong thing to do!
      FileUtils.rm_rf(cache.base_path_for(fetcher.cache_key))
      exit(exit_code)
    ensure
      cache.unlock(cache.base_path_for(fetcher.cache_key)) if fetcher.requires_locking?
    end
    assert_cache_sanity!
    [fetcher.archive_path, fetcher.writable?]
  end
end

#resolved_sourceObject



20
21
22
23
# File 'lib/inspec/cached_fetcher.rb', line 20

def resolved_source
  fetch
  @fetcher.resolved_source
end

#update_from_opts(_opts) ⇒ Object



25
26
27
# File 'lib/inspec/cached_fetcher.rb', line 25

def update_from_opts(_opts)
  false
end