mirror of
https://github.com/inspec/inspec
synced 2024-11-23 21:23:29 +00:00
add relative fetcher
This helps reduce any folder structures, weather on disk or in archives, to their relative root paths; i.e. ignore all file-prefixes that are given and go directly to the underlying files, relative to the common folders that contain it
This commit is contained in:
parent
f023d02bbb
commit
c9d1272f49
3 changed files with 113 additions and 2 deletions
|
@ -27,6 +27,66 @@ module Inspec
|
||||||
def read(_file)
|
def read(_file)
|
||||||
fail "Fetcher #{self} does not implement `read(...)`. This is required."
|
fail "Fetcher #{self} does not implement `read(...)`. This is required."
|
||||||
end
|
end
|
||||||
|
|
||||||
|
def relative_target
|
||||||
|
RelFetcher.new(self)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
class RelFetcher
|
||||||
|
attr_reader :files
|
||||||
|
|
||||||
|
def initialize(fetcher)
|
||||||
|
@parent = fetcher
|
||||||
|
@prefix = get_prefix(fetcher.files)
|
||||||
|
@files = fetcher.files.find_all { |x| x.start_with? @prefix }
|
||||||
|
.map { |x| x[@prefix.length..-1] }
|
||||||
|
end
|
||||||
|
|
||||||
|
def read(file)
|
||||||
|
@parent.read(@prefix + file)
|
||||||
|
end
|
||||||
|
|
||||||
|
private
|
||||||
|
|
||||||
|
def get_prefix(files)
|
||||||
|
return '' if files.empty?
|
||||||
|
sorted = files.sort_by(&:length)
|
||||||
|
get_folder_prefix(sorted)
|
||||||
|
end
|
||||||
|
|
||||||
|
def get_folder_prefix(files, first_iteration = true)
|
||||||
|
return get_files_prefix(files) if files.length == 1
|
||||||
|
pre = files[0] + File::SEPARATOR
|
||||||
|
rest = files[1..-1]
|
||||||
|
if rest.all? { |i| i.start_with? pre }
|
||||||
|
return get_folder_prefix(rest, false)
|
||||||
|
end
|
||||||
|
return get_files_prefix(files) if first_iteration
|
||||||
|
files
|
||||||
|
end
|
||||||
|
|
||||||
|
def get_files_prefix(files)
|
||||||
|
return '' if files.empty?
|
||||||
|
|
||||||
|
file = files[0]
|
||||||
|
bn = File.basename(file)
|
||||||
|
# no more prefixes
|
||||||
|
return '' if bn == file
|
||||||
|
|
||||||
|
i = file.rindex(bn)
|
||||||
|
prefix = file[0..i-1]
|
||||||
|
|
||||||
|
rest = files.find_all { |f| !f.start_with?(prefix) }
|
||||||
|
return prefix if rest.empty?
|
||||||
|
|
||||||
|
nu_prefix = get_prefix(rest)
|
||||||
|
return nu_prefix if prefix.start_with? nu_prefix
|
||||||
|
# edge case: completely different prefixes; retry prefix detection
|
||||||
|
a = File.dirname(prefix + 'a')
|
||||||
|
b = File.dirname(nu_prefix + 'b')
|
||||||
|
get_prefix([a, b])
|
||||||
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
|
@ -10,3 +10,52 @@ describe Inspec::Fetcher do
|
||||||
res.must_be_kind_of Fetchers::Local
|
res.must_be_kind_of Fetchers::Local
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
describe Inspec::Plugins::RelFetcher do
|
||||||
|
def fetcher
|
||||||
|
src_fetcher.expects(:files).returns(in_files).at_least_once
|
||||||
|
Inspec::Plugins::RelFetcher.new(src_fetcher)
|
||||||
|
end
|
||||||
|
|
||||||
|
let(:src_fetcher) { mock() }
|
||||||
|
|
||||||
|
IN_AND_OUT = {
|
||||||
|
[] => [],
|
||||||
|
%w{file} => %w{file},
|
||||||
|
# don't prefix just by filename
|
||||||
|
%w{file file_a} => %w{file file_a},
|
||||||
|
%w{path/file path/file_a} => %w{file file_a},
|
||||||
|
%w{path/to/file} => %w{file},
|
||||||
|
%w{/path/to/file} => %w{file},
|
||||||
|
%w{alice bob} => %w{alice bob},
|
||||||
|
# mixed paths
|
||||||
|
%w{x/a y/b} => %w{x/a y/b},
|
||||||
|
%w{/x/a /y/b} => %w{x/a y/b},
|
||||||
|
%w{z/x/a z/y/b} => %w{x/a y/b},
|
||||||
|
%w{/z/x/a /z/y/b} => %w{x/a y/b},
|
||||||
|
# mixed with relative path
|
||||||
|
%w{a path/to/b} => %w{a path/to/b},
|
||||||
|
%w{path/to/b a} => %w{path/to/b a},
|
||||||
|
%w{path/to/b path/a} => %w{to/b a},
|
||||||
|
%w{path/to/b path/a c} => %w{path/to/b path/a c},
|
||||||
|
# mixed with absolute paths
|
||||||
|
%w{/path/to/b /a} => %w{path/to/b a},
|
||||||
|
%w{/path/to/b /path/a} => %w{to/b a},
|
||||||
|
%w{/path/to/b /path/a /c} => %w{path/to/b path/a c},
|
||||||
|
# mixing absolute and relative paths
|
||||||
|
%w{path/a /path/b} => %w{path/a /path/b},
|
||||||
|
%w{/path/a path/b} => %w{/path/a path/b},
|
||||||
|
# extract folder structure buildup
|
||||||
|
%w{/a /a/b /a/b/c} => %w{c},
|
||||||
|
%w{/a /a/b /a/b/c/d/e} => %w{e},
|
||||||
|
}.each do |ins, outs|
|
||||||
|
describe 'empty profile' do
|
||||||
|
let(:in_files) { ins }
|
||||||
|
|
||||||
|
it 'also has no files' do
|
||||||
|
fetcher.files.must_equal outs
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
end
|
||||||
|
|
|
@ -32,7 +32,8 @@ describe Fetchers::Url do
|
||||||
end
|
end
|
||||||
|
|
||||||
it 'must contain all files' do
|
it 'must contain all files' do
|
||||||
_(res.files).must_equal ["inspec.yml", "libraries", "libraries/testlib.rb", "controls", "controls/filesystem_spec.rb"]
|
_(res.files).must_equal %w{inspec.yml libraries libraries/testlib.rb
|
||||||
|
controls controls/filesystem_spec.rb}
|
||||||
end
|
end
|
||||||
|
|
||||||
it 'must not read if the file isnt included' do
|
it 'must not read if the file isnt included' do
|
||||||
|
@ -60,7 +61,8 @@ describe Fetchers::Url do
|
||||||
end
|
end
|
||||||
|
|
||||||
it 'must contain all files' do
|
it 'must contain all files' do
|
||||||
_(res.files).must_equal ["inspec.yml", "controls", "controls/filesystem_spec.rb"]
|
_(res.files).must_equal %w{inspec.yml libraries libraries/testlib.rb
|
||||||
|
controls controls/filesystem_spec.rb}
|
||||||
end
|
end
|
||||||
|
|
||||||
it 'must not read if the file isnt included' do
|
it 'must not read if the file isnt included' do
|
||||||
|
|
Loading…
Reference in a new issue