diff options
author | John Keiser <jkeiser@opscode.com> | 2013-06-04 21:49:20 -0700 |
---|---|---|
committer | John Keiser <jkeiser@opscode.com> | 2013-06-07 13:12:36 -0700 |
commit | fa45b5705e6c3ed34ddd04da349dd7acecae583c (patch) | |
tree | 5499adab78236e9daabb22aa67d725edd21f1944 | |
parent | 79ee4c54bd0cee40098d280996741b147d0519f4 (diff) | |
download | chef-fa45b5705e6c3ed34ddd04da349dd7acecae583c.tar.gz |
Move ChefFSDataStore and config out to where they can be used by non-knife clients
-rw-r--r-- | lib/chef/chef_fs/chef_fs_data_store.rb | 371 | ||||
-rw-r--r-- | lib/chef/chef_fs/config.rb | 191 | ||||
-rw-r--r-- | lib/chef/chef_fs/knife.rb | 174 |
3 files changed, 585 insertions, 151 deletions
diff --git a/lib/chef/chef_fs/chef_fs_data_store.rb b/lib/chef/chef_fs/chef_fs_data_store.rb new file mode 100644 index 0000000000..41e1ca59ea --- /dev/null +++ b/lib/chef/chef_fs/chef_fs_data_store.rb @@ -0,0 +1,371 @@ +# +# Author:: John Keiser (<jkeiser@opscode.com>) +# Copyright:: Copyright (c) 2012 Opscode, Inc. +# License:: Apache License, Version 2.0 +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# + +require 'chef_zero/data_store/memory_store' +require 'chef_zero/data_store/data_already_exists_error' +require 'chef_zero/data_store/data_not_found_error' +require 'chef/chef_fs/file_pattern' +require 'chef/chef_fs/file_system' +require 'chef/chef_fs/file_system/not_found_error' +require 'chef/chef_fs/file_system/memory_root' + +class Chef + module ChefFS + class ChefFSDataStore + def initialize(chef_fs) + @chef_fs = chef_fs + @memory_store = ChefZero::DataStore::MemoryStore.new + end + + def chef_fs + @chef_fs.call + end + + MEMORY_PATHS = %w(sandboxes file_store) + + def create_dir(path, name, *options) + if use_memory_store?(path) + @memory_store.create_dir(path, name, *options) + else + with_dir(path) do |parent| + parent.create_child(chef_fs_filename(path + [name]), nil) + end + end + end + + def create(path, name, data, *options) + if use_memory_store?(path) + @memory_store.create(path, name, data, *options) + + elsif path[0] == 'cookbooks' && path.length == 2 + # Do nothing. The entry gets created when the cookbook is created. + + else + if !data.is_a?(String) + raise "set only works with strings" + end + + with_dir(path) do |parent| + parent.create_child(chef_fs_filename(path + [name]), data) + end + end + end + + def get(path, request=nil) + if use_memory_store?(path) + @memory_store.get(path) + + elsif path[0] == 'file_store' && path[1] == 'repo' + entry = Chef::ChefFS::FileSystem.resolve_path(chef_fs, path[2..-1].join('/')) + begin + entry.read + rescue Chef::ChefFS::FileSystem::NotFoundError => e + raise ChefZero::DataStore::DataNotFoundError.new(to_zero_path(e.entry), e) + end + + else + with_entry(path) do |entry| + if path[0] == 'cookbooks' && path.length == 3 + # get /cookbooks/NAME/version + result = entry.chef_object.to_hash + result.each_pair do |key, value| + if value.is_a?(Array) + value.each do |file| + if file.is_a?(Hash) && file.has_key?('checksum') + relative = ['file_store', 'repo', 'cookbooks'] + if Chef::Config.versioned_cookbooks + relative << "#{path[1]}-#{path[2]}" + else + relative << path[1] + end + relative = relative + file[:path].split('/') + file['url'] = ChefZero::RestBase::build_uri(request.base_uri, relative) + end + end + end + end + JSON.pretty_generate(result) + + else + entry.read + end + end + end + end + + def set(path, data, *options) + if use_memory_store?(path) + @memory_store.set(path, data, *options) + else + if !data.is_a?(String) + raise "set only works with strings: #{path} = #{data.inspect}" + end + + # Write out the files! + if path[0] == 'cookbooks' && path.length == 3 + write_cookbook(path, data, *options) + else + with_dir(path[0..-2]) do |parent| + parent.create_child(chef_fs_filename(path), data) + end + end + end + end + + def delete(path) + if use_memory_store?(path) + @memory_store.delete(path) + else + with_entry(path) do |entry| + if path[0] == 'cookbooks' && path.length >= 3 + entry.delete(true) + else + entry.delete + end + end + end + end + + def delete_dir(path, *options) + if use_memory_store?(path) + @memory_store.delete_dir(path, *options) + else + with_entry(path) do |entry| + entry.delete(options.include?(:recursive)) + end + end + end + + def list(path) + if use_memory_store?(path) + @memory_store.list(path) + + elsif path[0] == 'cookbooks' && path.length == 1 + with_entry(path) do |entry| + begin + if Chef::Config.versioned_cookbooks + # /cookbooks/name-version -> /cookbooks/name + entry.children.map { |child| split_name_version(child.name)[0] }.uniq + else + entry.children.map { |child| child.name } + end + rescue Chef::ChefFS::FileSystem::NotFoundError + # If the cookbooks dir doesn't exist, we have no cookbooks (not 404) + [] + end + end + + elsif path[0] == 'cookbooks' && path.length == 2 + if Chef::Config.versioned_cookbooks + # list /cookbooks/name = filter /cookbooks/name-version down to name + entry.children.map { |child| split_name_version(child.name) }. + select { |name, version| name == path[1] }. + map { |name, version| version }.to_a + else + # list /cookbooks/name = <single version> + version = get_single_cookbook_version(path) + [version] + end + + else + with_entry(path) do |entry| + begin + entry.children.map { |c| zero_filename(c) }.sort + rescue Chef::ChefFS::FileSystem::NotFoundError + # /cookbooks, /data, etc. never return 404 + if path_always_exists?(path) + [] + else + raise + end + end + end + end + end + + def exists?(path) + if use_memory_store?(path) + @memory_store.exists?(path) + else + path_always_exists?(path) || Chef::ChefFS::FileSystem.resolve_path(chef_fs, to_chef_fs_path(path)).exists? + end + end + + def exists_dir?(path) + if use_memory_store?(path) + @memory_store.exists_dir?(path) + elsif path[0] == 'cookbooks' && path.length == 2 + list([ path[0] ]).include?(path[1]) + else + Chef::ChefFS::FileSystem.resolve_path(chef_fs, to_chef_fs_path(path)).exists? + end + end + + private + + def use_memory_store?(path) + return path[0] == 'sandboxes' || path[0] == 'file_store' && path[1] == 'checksums' || path == [ 'environments', '_default' ] + end + + def write_cookbook(path, data, *options) + # Create a little Chef::ChefFS memory filesystem with the data + if Chef::Config.versioned_cookbooks + cookbook_path = "cookbooks/#{path[1]}-#{path[2]}" + else + cookbook_path = "cookbooks/#{path[1]}" + end + cookbook_fs = Chef::ChefFS::FileSystem::MemoryRoot.new('uploading') + cookbook = JSON.parse(data, :create_additions => false) + cookbook.each_pair do |key, value| + if value.is_a?(Array) + value.each do |file| + if file.is_a?(Hash) && file.has_key?('checksum') + file_data = @memory_store.get(['file_store', 'checksums', file['checksum']]) + cookbook_fs.add_file("#{cookbook_path}/#{file['path']}", file_data) + end + end + end + end + + # Use the copy/diff algorithm to copy it down so we don't destroy + # chefignored data. This is terribly un-thread-safe. + Chef::ChefFS::FileSystem.copy_to(Chef::ChefFS::FilePattern.new("/#{cookbook_path}"), cookbook_fs, chef_fs, nil, {:purge => true}) + end + + def split_name_version(entry_name) + name_version = entry_name.split('-') + name = name_version[0..-2].join('-') + version = name_version[-1] + [name,version] + end + + def to_chef_fs_path(path) + _to_chef_fs_path(path).join('/') + end + + def chef_fs_filename(path) + _to_chef_fs_path(path)[-1] + end + + def _to_chef_fs_path(path) + if path[0] == 'data' + path = path.dup + path[0] = 'data_bags' + if path.length >= 3 + path[2] = "#{path[2]}.json" + end + elsif path[0] == 'cookbooks' + if path.length == 2 + raise ChefZero::DataStore::DataNotFoundError.new(path) + elsif Chef::Config.versioned_cookbooks + if path.length >= 3 + # cookbooks/name/version -> cookbooks/name-version + path = [ path[0], "#{path[1]}-#{path[2]}" ] + path[3..-1] + end + else + if path.length >= 3 + # cookbooks/name/version/... -> /cookbooks/name/... iff metadata says so + version = get_single_cookbook_version(path) + if path[2] == version + path = path[0..1] + path[3..-1] + else + raise ChefZero::DataStore::DataNotFoundError.new(path) + end + end + end + elsif path.length == 2 + path = path.dup + path[1] = "#{path[1]}.json" + end + path + end + + def to_zero_path(entry) + path = entry.path.split('/')[1..-1] + if path[0] == 'data_bags' + path = path.dup + path[0] = 'data' + if path.length >= 3 + path[2] = path[2][0..-6] + end + + elsif path[0] == 'cookbooks' + if Chef::Config.versioned_cookbooks + # cookbooks/name-version/... -> cookbooks/name/version/... + if path.length >= 2 + name, version = split_name_version(path[1]) + path = [ path[0], name, version ] + path[2..-1] + end + else + if path.length >= 2 + # cookbooks/name/... -> cookbooks/name/version/... + version = get_single_cookbook_version(path) + path = path[0..1] + [version] + path[2..-1] + end + end + + elsif path.length == 2 && path[0] != 'cookbooks' + path = path.dup + path[1] = path[1][0..-6] + end + path + end + + def zero_filename(entry) + to_zero_path(entry)[-1] + end + + def path_always_exists?(path) + return path.length == 1 && %w(clients cookbooks data environments nodes roles users).include?(path[0]) + end + + def with_entry(path) + begin + yield Chef::ChefFS::FileSystem.resolve_path(chef_fs, to_chef_fs_path(path)) + rescue Chef::ChefFS::FileSystem::NotFoundError => e + raise ChefZero::DataStore::DataNotFoundError.new(to_zero_path(e.entry), e) + end + end + + def with_dir(path) + begin + yield get_dir(_to_chef_fs_path(path), true) + rescue Chef::ChefFS::FileSystem::NotFoundError => e + raise ChefZero::DataStore::DataNotFoundError.new(to_zero_path(e.entry), e) + end + end + + def get_dir(path, create=false) + result = Chef::ChefFS::FileSystem.resolve_path(chef_fs, path.join('/')) + if result.exists? + result + elsif create + get_dir(path[0..-2], create).create_child(result.name, nil) + else + raise ChefZero::DataStore::DataNotFoundError.new(path) + end + end + + def get_single_cookbook_version(path) + dir = Chef::ChefFS::FileSystem.resolve_path(chef_fs, path[0..1].join('/')) + metadata = ChefZero::CookbookData.metadata_from(dir, path[1], nil, []) + metadata[:version] || '0.0.0' + end + end + end +end diff --git a/lib/chef/chef_fs/config.rb b/lib/chef/chef_fs/config.rb new file mode 100644 index 0000000000..4a8ca26ee8 --- /dev/null +++ b/lib/chef/chef_fs/config.rb @@ -0,0 +1,191 @@ +# +# Author:: John Keiser (<jkeiser@opscode.com>) +# Copyright:: Copyright (c) 2012 Opscode, Inc. +# License:: Apache License, Version 2.0 +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# + +require 'chef/log' +require 'chef/chef_fs/path_utils' + +class Chef + module ChefFS + # + # Helpers to take Chef::Config and create chef_fs and local_fs from it + # + class Config + def initialize(chef_config = Chef::Config, cwd = Dir.pwd) + @chef_config = chef_config + @cwd = cwd + configure_repo_paths + end + + PATH_VARIABLES = %w(acl_path client_path cookbook_path container_path data_bag_path environment_path group_path node_path role_path user_path) + + def chef_fs + @chef_fs ||= create_chef_fs + end + + def create_chef_fs + require 'chef/chef_fs/file_system/chef_server_root_dir' + Chef::ChefFS::FileSystem::ChefServerRootDir.new("remote", @chef_config) + end + + def local_fs + @local_fs ||= create_local_fs + end + + def create_local_fs + require 'chef/chef_fs/file_system/chef_repository_file_system_root_dir' + Chef::ChefFS::FileSystem::ChefRepositoryFileSystemRootDir.new(object_paths) + end + + # Returns the given real path's location relative to the server root. + # + # If chef_repo is /home/jkeiser/chef_repo, + # and pwd is /home/jkeiser/chef_repo/cookbooks, + # server_path('blah') == '/cookbooks/blah' + # server_path('../roles/blah.json') == '/roles/blah' + # server_path('../../readme.txt') == nil + # server_path('*/*ab*') == '/cookbooks/*/*ab*' + # server_path('/home/jkeiser/chef_repo/cookbooks/blah') == '/cookbooks/blah' + # server_path('/home/*/chef_repo/cookbooks/blah') == nil + # + # If there are multiple paths (cookbooks, roles, data bags, etc. can all + # have separate paths), and cwd+the path reaches into one of them, we will + # return a path relative to that. Otherwise we will return a path to + # chef_repo. + # + # Globs are allowed as well, but globs outside server paths are NOT + # (presently) supported. See above examples. TODO support that. + # + # If the path does not reach into ANY specified directory, nil is returned. + def server_path(file_path) + pwd = File.expand_path(Dir.pwd) + absolute_path = Chef::ChefFS::PathUtils.realest_path(File.expand_path(file_path, pwd)) + + # Check all object paths (cookbooks_dir, data_bags_dir, etc.) + object_paths.each_pair do |name, paths| + paths.each do |path| + realest_path = Chef::ChefFS::PathUtils.realest_path(path) + if absolute_path[0,realest_path.length] == realest_path && + (absolute_path.length == realest_path.length || + absolute_path[realest_path.length,1] =~ /#{PathUtils.regexp_path_separator}/) + relative_path = Chef::ChefFS::PathUtils::relative_to(absolute_path, realest_path) + return relative_path == '.' ? "/#{name}" : "/#{name}/#{relative_path}" + end + end + end + + # Check chef_repo_path + Array(@chef_config[:chef_repo_path]).flatten.each do |chef_repo_path| + realest_chef_repo_path = Chef::ChefFS::PathUtils.realest_path(chef_repo_path) + if absolute_path == realest_chef_repo_path + return '/' + end + end + + nil + end + + # The current directory, relative to server root + def base_path + @base_path ||= server_path(File.expand_path(@cwd)) + end + + # Print the given server path, relative to the current directory + def format_path(entry) + server_path = entry.path + if base_path && server_path[0,base_path.length] == base_path + if server_path == base_path + return "." + elsif server_path[base_path.length,1] == "/" + return server_path[base_path.length + 1, server_path.length - base_path.length - 1] + elsif base_path == "/" && server_path[0,1] == "/" + return server_path[1, server_path.length - 1] + end + end + server_path + end + + private + + def object_paths + @object_paths ||= begin + if !@chef_config[:chef_repo_path] + Chef::Log.error("Must specify either chef_repo_path or cookbook_path in Chef config file") + exit(1) + end + + result = {} + case @chef_config[:repo_mode] + when 'static' + object_names = %w(cookbooks data_bags environments roles) + when 'hosted_everything' + object_names = %w(acls clients cookbooks containers data_bags environments groups nodes roles) + else + object_names = %w(clients cookbooks data_bags environments nodes roles users) + end + object_names.each do |object_name| + variable_name = "#{object_name[0..-2]}_path" # cookbooks -> cookbook_path + paths = Array(@chef_config[variable_name]).flatten + result[object_name] = paths.map { |path| File.expand_path(path) } + end + result + end + end + + def configure_repo_paths + # Infer chef_repo_path from cookbook_path if not speciifed + if !@chef_config[:chef_repo_path] + if @chef_config[:cookbook_path] + @chef_config[:chef_repo_path] = Array(@chef_config[:cookbook_path]).flatten.map { |path| File.expand_path('..', path) } + end + end + + # Smooth out some (for now) inappropriate defaults set by Chef + if @chef_config[:data_bag_path] == @chef_config.platform_specific_path('/var/chef/data_bags') + @chef_config[:data_bag_path] = nil + end + if @chef_config[:node_path] == '/var/chef/node' + @chef_config[:node_path] = nil + end + if @chef_config[:role_path] == @chef_config.platform_specific_path('/var/chef/roles') + @chef_config[:role_path] = nil + end + + # Default to getting *everything* from the server. + if !@chef_config[:repo_mode] + if @chef_config[:chef_server_url] =~ /\/+organizations\/.+/ + @chef_config[:repo_mode] = 'hosted_everything' + else + @chef_config[:repo_mode] = 'everything' + end + end + + # Infer any *_path variables that are not specified + if @chef_config[:chef_repo_path] + PATH_VARIABLES.each do |variable_name| + chef_repo_paths = Array(@chef_config[:chef_repo_path]).flatten + variable = variable_name.to_sym + if !@chef_config[variable] + # cookbook_path -> cookbooks + @chef_config[variable] = chef_repo_paths.map { |path| File.join(path, "#{variable_name[0..-6]}s") } + end + end + end + end + end + end +end diff --git a/lib/chef/chef_fs/knife.rb b/lib/chef/chef_fs/knife.rb index f68cec8971..46b30cacbe 100644 --- a/lib/chef/chef_fs/knife.rb +++ b/lib/chef/chef_fs/knife.rb @@ -24,14 +24,20 @@ class Chef # Workaround for CHEF-3932 def self.deps super do - require 'chef/chef_fs/file_system/chef_server_root_dir' - require 'chef/chef_fs/file_system/chef_repository_file_system_root_dir' + require 'chef/config' + require 'chef/chef_fs/parallelizer' + require 'chef/chef_fs/config' require 'chef/chef_fs/file_pattern' require 'chef/chef_fs/path_utils' - require 'chef/chef_fs/parallelizer' - require 'chef/config' yield end + end + + def self.inherited(c) + super + # Ensure we always get to do our includes, whether subclass calls deps or not + c.deps do + end option :repo_mode, :long => '--repo-mode MODE', @@ -46,176 +52,38 @@ class Chef :description => 'Maximum number of simultaneous requests to send (default: 10)' end - def self.inherited(c) - super - # Ensure we always get to do our includes, whether subclass calls deps or not - c.deps do - end - end - def configure_chef super Chef::Config[:repo_mode] = config[:repo_mode] if config[:repo_mode] Chef::Config[:concurrency] = config[:concurrency].to_i if config[:concurrency] # --chef-repo-path overrides all other paths - path_variables = %w(acl_path client_path cookbook_path container_path data_bag_path environment_path group_path node_path role_path user_path) if config[:chef_repo_path] Chef::Config[:chef_repo_path] = config[:chef_repo_path] - path_variables.each do |variable_name| - Chef::Config[variable_name.to_sym] = nil - end - end - - # Infer chef_repo_path from cookbook_path if not speciifed - if !Chef::Config[:chef_repo_path] - if Chef::Config[:cookbook_path] - Chef::Config[:chef_repo_path] = Array(Chef::Config[:cookbook_path]).flatten.map { |path| File.expand_path('..', path) } - end - end - - # Smooth out some (for now) inappropriate defaults set by Chef - if Chef::Config[:data_bag_path] == Chef::Config.platform_specific_path('/var/chef/data_bags') - Chef::Config[:data_bag_path] = nil - end - if Chef::Config[:node_path] == '/var/chef/node' - Chef::Config[:node_path] = nil - end - if Chef::Config[:role_path] == Chef::Config.platform_specific_path('/var/chef/roles') - Chef::Config[:role_path] = nil - end - - # Default to getting *everything* from the server. - if !Chef::Config[:repo_mode] - if Chef::Config[:chef_server_url] =~ /\/+organizations\/.+/ - Chef::Config[:repo_mode] = 'hosted_everything' - else - Chef::Config[:repo_mode] = 'everything' + Chef::ChefFS::Config::PATH_VARIABLES.each do |variable_name| + Chef::Config[variable_name.to_sym] = chef_repo_paths.map { |path| File.join(path, "#{variable_name[0..-6]}s") } end end - # Infer any *_path variables that are not specified - if Chef::Config[:chef_repo_path] - path_variables.each do |variable_name| - chef_repo_paths = Array(Chef::Config[:chef_repo_path]).flatten - variable = variable_name.to_sym - if !Chef::Config[variable] - # cookbook_path -> cookbooks - Chef::Config[variable] = chef_repo_paths.map { |path| File.join(path, "#{variable_name[0..-6]}s") } - end - end - end + @chef_fs_config = Chef::ChefFS::Config.new(Chef::Config) Chef::ChefFS::Parallelizer.threads = (Chef::Config[:concurrency] || 10) - 1 end def chef_fs - @chef_fs ||= create_chef_fs + @chef_fs_config.chef_fs end def create_chef_fs - Chef::ChefFS::FileSystem::ChefServerRootDir.new("remote", Chef::Config) - end - - def object_paths - @object_paths ||= begin - if !Chef::Config[:chef_repo_path] - Chef::Log.error("Must specify either chef_repo_path or cookbook_path in Chef config file") - exit(1) - end - - result = {} - case Chef::Config[:repo_mode] - when 'static' - object_names = %w(cookbooks data_bags environments roles) - when 'hosted_everything' - object_names = %w(acls clients cookbooks containers data_bags environments groups nodes roles) - else - object_names = %w(clients cookbooks data_bags environments nodes roles users) - end - object_names.each do |object_name| - variable_name = "#{object_name[0..-2]}_path" # cookbooks -> cookbook_path - paths = Array(Chef::Config[variable_name]).flatten - result[object_name] = paths.map { |path| File.expand_path(path) } - end - result - end - end - - # Returns the given real path's location relative to the server root. - # - # If chef_repo is /home/jkeiser/chef_repo, - # and pwd is /home/jkeiser/chef_repo/cookbooks, - # server_path('blah') == '/cookbooks/blah' - # server_path('../roles/blah.json') == '/roles/blah' - # server_path('../../readme.txt') == nil - # server_path('*/*ab*') == '/cookbooks/*/*ab*' - # server_path('/home/jkeiser/chef_repo/cookbooks/blah') == '/cookbooks/blah' - # server_path('/home/*/chef_repo/cookbooks/blah') == nil - # - # If there are multiple paths (cookbooks, roles, data bags, etc. can all - # have separate paths), and cwd+the path reaches into one of them, we will - # return a path relative to that. Otherwise we will return a path to - # chef_repo. - # - # Globs are allowed as well, but globs outside server paths are NOT - # (presently) supported. See above examples. TODO support that. - # - # If the path does not reach into ANY specified directory, nil is returned. - def server_path(file_path) - pwd = File.expand_path(Dir.pwd) - absolute_path = Chef::ChefFS::PathUtils.realest_path(File.expand_path(file_path, pwd)) - - # Check all object paths (cookbooks_dir, data_bags_dir, etc.) - object_paths.each_pair do |name, paths| - paths.each do |path| - realest_path = Chef::ChefFS::PathUtils.realest_path(path) - if absolute_path[0,realest_path.length] == realest_path && - (absolute_path.length == realest_path.length || - absolute_path[realest_path.length,1] =~ /#{PathUtils.regexp_path_separator}/) - relative_path = Chef::ChefFS::PathUtils::relative_to(absolute_path, realest_path) - return relative_path == '.' ? "/#{name}" : "/#{name}/#{relative_path}" - end - end - end - - # Check chef_repo_path - Array(Chef::Config[:chef_repo_path]).flatten.each do |chef_repo_path| - realest_chef_repo_path = Chef::ChefFS::PathUtils.realest_path(chef_repo_path) - if absolute_path == realest_chef_repo_path - return '/' - end - end - - nil - end - - # The current directory, relative to server root - def base_path - @base_path ||= server_path(File.expand_path(Dir.pwd)) - end - - # Print the given server path, relative to the current directory - def format_path(entry) - server_path = entry.path - if base_path && server_path[0,base_path.length] == base_path - if server_path == base_path - return "." - elsif server_path[base_path.length,1] == "/" - return server_path[base_path.length + 1, server_path.length - base_path.length - 1] - elsif base_path == "/" && server_path[0,1] == "/" - return server_path[1, server_path.length - 1] - end - end - server_path + @chef_fs_config.create_chef_fs end def local_fs - @local_fs ||= create_local_fs + @chef_fs_config.local_fs end def create_local_fs - Chef::ChefFS::FileSystem::ChefRepositoryFileSystemRootDir.new(object_paths) + @chef_fs_config.create_local_fs end def pattern_args @@ -226,14 +94,18 @@ class Chef # TODO support absolute file paths and not just patterns? Too much? # Could be super useful in a world with multiple repo paths args.map do |arg| - if !base_path && !PathUtils.is_absolute?(arg) + if !@chef_fs_config.base_path && !Chef::ChefFS::PathUtils.is_absolute?(arg) ui.error("Attempt to use relative path '#{arg}' when current directory is outside the repository path") exit(1) end - Chef::ChefFS::FilePattern::relative_to(base_path, arg) + Chef::ChefFS::FilePattern::relative_to(@chef_fs_config.base_path, arg) end end + def format_path(entry) + @chef_fs_config.format_path(entry) + end + def parallelize(inputs, options = {}, &block) Chef::ChefFS::Parallelizer.parallelize(inputs, options, &block) end |