Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Fix recursive deps for path-based deps #929

Merged
merged 1 commit into from
Aug 18, 2016
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 5 additions & 2 deletions lib/fetchers/local.rb
Original file line number Diff line number Diff line change
Expand Up @@ -10,8 +10,11 @@ class Local < Inspec.fetcher(1)
attr_reader :files

def self.resolve(target)
return nil unless File.exist?(target)
new(target)
if !File.exist?(target)
nil
else
new(target)
end
end

def initialize(target)
Expand Down
66 changes: 8 additions & 58 deletions lib/inspec/dependencies.rb
Original file line number Diff line number Diff line change
Expand Up @@ -6,23 +6,25 @@
require 'fileutils'
require 'molinillo'
require 'inspec/errors'
require 'inspec/requirement'

module Inspec
class Resolver
def self.resolve(requirements, vendor_index, cwd, opts = {})
reqs = requirements.map do |req|
Requirement.from_metadata(req, cwd: cwd) ||
fail("Cannot initialize dependency: #{req}")
req = Inspec::Requirement.from_metadata(req, cwd: cwd)
req || fail("Cannot initialize dependency: #{req}")
end

new(vendor_index, opts).resolve(reqs)
new(vendor_index, opts.merge(cwd: cwd)).resolve(reqs)
end

def initialize(vendor_index, opts = {})
@logger = opts[:logger] || Logger.new(nil)
@debug_mode = false # TODO: hardcoded for now, grab from options

@vendor_index = vendor_index
@cwd = opts[:cwd] || './'
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I would move that to the cli and set the default there, not as part of the code.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Maybe we can reuse the profile path here to avoid adding a new option? Overall I think we'll need to refactor a lot of this current working directory as it is currently very confusing. Once we have the fetchers/vendoring more flushed out, I think this level of the code won't need to worry about this.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

👍

@resolver = Molinillo::Resolver.new(self, self)
@search_cache = {}
end
Expand Down Expand Up @@ -87,7 +89,9 @@ def uncached_search_for(dep)
# @return [Array<Object>] the dependencies that are required by the given
# `specification`.
def dependencies_for(specification)
specification.profile.metadata.dependencies
specification.profile.metadata.dependencies.map do |r|
Inspec::Requirement.from_metadata(r, cwd: @cwd)
end
end

# Determines whether the given `requirement` is satisfied by the given
Expand Down Expand Up @@ -208,60 +212,6 @@ def load_path(_path)
end
end

class Requirement
attr_reader :name, :dep, :cwd, :opts
def initialize(name, dep, cwd, opts)
@name = name
@dep = Gem::Dependency.new(name, Gem::Requirement.new(Array(dep)), :runtime)
@opts = opts
@cwd = cwd
end

def matches_spec?(spec)
params = spec.profile.metadata.params
@dep.match?(params[:name], params[:version])
end

def pull
case
when @opts[:path] then pull_path(@opts[:path])
else
# TODO: should default to supermarket
fail 'You must specify the source of the dependency (for now...)'
end
end

def path
@path || pull
end

def profile
return nil if path.nil?
@profile ||= Inspec::Profile.for_target(path, {})
end

def self.from_metadata(dep, opts)
fail 'Cannot load empty dependency.' if dep.nil? || dep.empty?
name = dep[:name] || fail('You must provide a name for all dependencies')
version = dep[:version]
new(name, version, opts[:cwd], dep)
end

def to_s
@dep.to_s
end

private

def pull_path(path)
abspath = File.absolute_path(path, @cwd)
fail "Dependency path doesn't exist: #{path}" unless File.exist?(abspath)
fail "Dependency path isn't a folder: #{path}" unless File.directory?(abspath)
@path = abspath
true
end
end

class SupermarketDependency
def initialize(url, requirement)
@url = url
Expand Down
44 changes: 44 additions & 0 deletions lib/inspec/requirement.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
# encoding: utf-8
module Inspec
class Requirement
attr_reader :name, :dep, :cwd, :opts
def initialize(name, version_constraints, cwd, opts)
@name = name
@dep = Gem::Dependency.new(name,
Gem::Requirement.new(Array(version_constraints)),
:runtime)
@opts = opts
@cwd = cwd
end

def matches_spec?(spec)
params = spec.profile.metadata.params
@dep.match?(params[:name], params[:version])
end

def pull
case
when @opts[:path]
File.expand_path(@opts[:path], @cwd)
else
fail 'You must specify the source of the dependency (for now...)'
end
end

def path
@path ||= pull
end

def profile
return nil if path.nil?
@profile ||= Inspec::Profile.for_target(path, {})
end

def self.from_metadata(dep, opts)
fail 'Cannot load empty dependency.' if dep.nil? || dep.empty?
name = dep[:name] || fail('You must provide a name for all dependencies')
version = dep[:version]
new(name, version, opts[:cwd], opts.merge(dep))
end
end
end
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
# encoding: utf-8

include_controls 'profile_a'
include_controls 'profile_b'
12 changes: 12 additions & 0 deletions test/unit/mock/profiles/dependencies-file/inheritance/inspec.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
name: inheritance
title: InSpec example inheritance
maintainer: Chef Software, Inc.
copyright: Chef Software, Inc.
copyright_email: support@chef.io
license: Apache 2 license
version: 1.0.0
depends:
- name: profile_a
path: ../profile_a
- name: profile_b
path: ../profile_b
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
# encoding: utf-8
# copyright: 2015, The Authors
# license: All rights reserved

title 'sample section'
include_controls 'profile_c'

# you can also use plain tests
describe file('/tmp') do
it { should be_directory }
end

# you add controls here
control 'tmp-1.0' do # A unique ID for this control
impact 0.7 # The criticality, if this control fails.
title 'Create /tmp directory' # A human-readable title
desc 'An optional description...'
describe file('/tmp') do # The actual test
it { should be_directory }
end
end
11 changes: 11 additions & 0 deletions test/unit/mock/profiles/dependencies-file/profile_a/inspec.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
name: profile_a
title: InSpec Profile
maintainer: The Authors
copyright: The Authors
copyright_email: you@example.com
license: All Rights Reserved
summary: An InSpec Compliance Profile
version: 0.1.0
depends:
- name: profile_c
path: ../profile_c
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
# encoding: utf-8
# copyright: 2015, The Authors
# license: All rights reserved

title 'sample section'

# you can also use plain tests
describe file('/tmp') do
it { should be_directory }
end

# you add controls here
control 'tmp-1.0' do # A unique ID for this control
impact 0.7 # The criticality, if this control fails.
title 'Create /tmp directory' # A human-readable title
desc 'An optional description...'
describe file('/tmp') do # The actual test
it { should be_directory }
end
end
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
name: profile_b
title: InSpec Profile
maintainer: The Authors
copyright: The Authors
copyright_email: you@example.com
license: All Rights Reserved
summary: An InSpec Compliance Profile
version: 0.1.0
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
name: profile_c
title: InSpec Profile
maintainer: The Authors
copyright: The Authors
copyright_email: you@example.com
license: All Rights Reserved
summary: An InSpec Compliance Profile
version: 0.1.0
Empty file.