summaryrefslogtreecommitdiff
path: root/lib/chef/chef_fs/knife.rb
diff options
context:
space:
mode:
authorjkeiser <jkeiser@opscode.com>2012-12-17 13:24:23 -0800
committerJohn Keiser <jkeiser@opscode.com>2013-06-07 13:12:12 -0700
commit02daf8327204f5229e432a8e2cf7ab94f1c434a9 (patch)
tree0440af7a0f73eac4d16b0bc1358236144bc95b2b /lib/chef/chef_fs/knife.rb
parent777ad0c423a6f15804d328e407c014e627de5419 (diff)
downloadchef-02daf8327204f5229e432a8e2cf7ab94f1c434a9.tar.gz
Support chef_repo_path, roles_path, multiple cookbook_paths
Diffstat (limited to 'lib/chef/chef_fs/knife.rb')
-rw-r--r--lib/chef/chef_fs/knife.rb128
1 files changed, 110 insertions, 18 deletions
diff --git a/lib/chef/chef_fs/knife.rb b/lib/chef/chef_fs/knife.rb
index 8a116d980e..dc4b67e5ae 100644
--- a/lib/chef/chef_fs/knife.rb
+++ b/lib/chef/chef_fs/knife.rb
@@ -32,36 +32,124 @@ class Chef
:description => "Specifies the local repository layout. Values: default or full"
end
- def base_path
- @base_path ||= begin
- relative_to_base = Chef::ChefFS::PathUtils::relative_to(File.expand_path(Dir.pwd), chef_repo)
- relative_to_base == '.' ? '/' : "/#{relative_to_base}"
+ def chef_fs
+ @chef_fs ||= Chef::ChefFS::FileSystem::ChefServerRootDir.new("remote", Chef::Config, config[:repo_mode])
+ end
+
+ def chef_repo_path
+ @chef_repo_path ||= begin
+ if Chef::Config.chef_repo_path
+ File.expand_path(Chef::Config.chef_repo_path)
+ elsif Chef::Config.cookbook_path
+ File.expand_path('..', Array(Chef::Config.cookbook_path).flatten.first)
+ else
+ nil
+ end
end
end
- def chef_fs
- @chef_fs ||= Chef::ChefFS::FileSystem::ChefServerRootDir.new("remote", Chef::Config, config[:repo_mode])
+ # Smooth out some inappropriate (for know) variable defaults in Chef.
+ def config_var(name)
+ case name
+ when :data_bag_path
+ Chef::Config[name] == Chef::Config.platform_specific_path('/var/chef/data_bags') ? nil : Chef::Config[name]
+ when :node_path
+ Chef::Config[name] == '/var/chef/node' ? nil : Chef::Config[name]
+ when :role_path
+ Chef::Config[name] == Chef::Config.platform_specific_path('/var/chef/roles') ? nil : Chef::Config[name]
+ when :chef_repo_path
+ chef_repo_path
+ else
+ Chef::Config[name]
+ end
end
- def chef_repo
- @chef_repo ||= File.expand_path(File.join(Chef::Config.cookbook_path, ".."))
+ def object_paths
+ @object_paths ||= begin
+ result = {}
+ %w(clients cookbooks data_bags environments nodes roles users).each do |object_name|
+ variable_name = "#{object_name[0..-2]}_path" # cookbooks -> cookbook_path
+ paths = config_var(variable_name.to_sym)
+ if !paths
+ if !chef_repo_path
+ # TODO if chef_repo is not specified and repo_mode does not require
+ # clients/users/nodes, don't require them to be specified.
+ Chef::Log.error("Must specify either chef_repo_path or #{variable_name} in Chef config file")
+ exit(1)
+ end
+ paths = File.join(chef_repo_path, object_name)
+ end
+ paths = Array(paths).flatten.map { |path| File.expand_path(path) }
+ result[object_name] = paths
+ end
+ result
+ end
end
- def format_path(path)
- if path[0,base_path.length] == base_path
- if path == base_path
+ # 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 = 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|
+ if absolute_path[0,path.length] == path
+ relative_path = Chef::ChefFS::PathUtils::relative_to(path, absolute_path)
+ return relative_path == '.' ? "/#{name}" : "/#{name}/#{relative_path}"
+ end
+ end
+ end
+
+ # Check chef_repo_path
+ if chef_repo_path[0,absolute_path.length] == absolute_path
+ relative_path = Chef::ChefFS::PathUtils::relative_to(chef_repo_path, absolute_path)
+ return relative_path == '.' ? '/' : "/#{relative_path}"
+ 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(server_path)
+ if server_path[0,base_path.length] == base_path
+ if server_path == base_path
return "."
- elsif path[base_path.length] == "/"
- return path[base_path.length + 1, path.length - base_path.length - 1]
- elsif base_path == "/" && path[0] == "/"
- return path[1, path.length - 1]
+ elsif server_path[base_path.length] == "/"
+ return server_path[base_path.length + 1, server_path.length - base_path.length - 1]
+ elsif base_path == "/" && server_path[0] == "/"
+ return server_path[1, server_path.length - 1]
end
end
- path
+ server_path
end
def local_fs
- @local_fs ||= Chef::ChefFS::FileSystem::ChefRepositoryFileSystemRootDir.new(chef_repo)
+ @local_fs ||= Chef::ChefFS::FileSystem::ChefRepositoryFileSystemRootDir.new(object_paths)
end
def pattern_args
@@ -69,7 +157,11 @@ class Chef
end
def pattern_args_from(args)
- args.map { |arg| Chef::ChefFS::FilePattern::relative_to(base_path, arg) }.to_a
+ # 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|
+ Chef::ChefFS::FilePattern::relative_to(base_path, arg)
+ end
end
end