class Inspec::Resolver


implementation of the fetcher being used.
Currently the fetching happens somewhat lazily depending on the
of the same profile being used at runtime.
will provide the isolation necessary to support multiple versions
The full dependency tree is then available for the loader, which
specified version constraint
- Checks that the specified dependency source satisfies the
- Checks the presence of cycles, and
- Fetches the dependency from the source
and:
to a single version. Rather, it traverses down the dependency tree
or Berkshelf, it does not attempt to resolve each named dependency
Inspec::Resolver is a simple dependency resolver. Unlike Bundler

def self.resolve(dependencies, cache, working_dir, backend)

def self.resolve(dependencies, cache, working_dir, backend)
  reqs = dependencies.map do |dep|
    req = Inspec::Requirement.from_metadata(dep, cache, cwd: working_dir, backend: backend)
    req || raise("Cannot initialize dependency: #{req}")
  end
  new.resolve(reqs)
end

def detect_duplicates(deps, top_level, path_string)

def detect_duplicates(deps, top_level, path_string)
  seen_items_local = []
  deps.each do |dep|
    if seen_items_local.include?(dep.name)
      problem_cookbook = if top_level
                           'the inspec.yml for this profile.'
                         else
                           "the dependency information for #{path_string.split(' ').last}"
                         end
      raise Inspec::DuplicateDep, "The dependency #{dep.name} is listed twice in #{problem_cookbook}"
    else
      seen_items_local << dep.name
    end
  end
end

def resolve(deps, top_level = true, seen_items = {}, path_string = '') # rubocop:disable Metrics/AbcSize

rubocop:disable Metrics/AbcSize
def resolve(deps, top_level = true, seen_items = {}, path_string = '') # rubocop:disable Metrics/AbcSize
  graph = {}
  if top_level
    Inspec::Log.debug("Starting traversal of dependencies #{deps.map(&:to_s)}")
  else
    Inspec::Log.debug("Traversing dependency tree of transitive dependency #{deps.map(&:name)}")
  end
  detect_duplicates(deps, top_level, path_string)
  deps.each do |dep|
    new_seen_items = seen_items.dup
    new_path_string = if path_string.empty?
                        dep.name
                      else
                        path_string + " -> #{dep.name}"
                      end
    raise Inspec::CyclicDependencyError, "Dependency #{dep} would cause a dependency cycle (#{new_path_string})" if new_seen_items.key?(dep.resolved_source)
    new_seen_items[dep.resolved_source] = true
    if !dep.source_satisfies_spec?
      raise Inspec::UnsatisfiedVersionSpecification, "The profile #{dep.name} from #{dep.resolved_source} has a version #{dep.source_version} which doesn't match #{dep.version_constraints}"
    end
    Inspec::Log.debug("Adding dependency #{dep.name} (#{dep.resolved_source})")
    graph[dep.name] = dep
    if !dep.dependencies.empty?
      resolve(dep.dependencies, false, new_seen_items.dup, new_path_string)
    end
  end
  Inspec::Log.debug('Dependency traversal complete.') if top_level
  graph
end