Created
December 12, 2013 18:19
-
-
Save dhoer/7932740 to your computer and use it in GitHub Desktop.
Adds version info to knife deps output. Kudos to bjbishop for providing this hack.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
require 'chef/chef_fs/knife' | |
class Chef | |
class Knife | |
class Deps < Chef::ChefFS::Knife | |
banner "knife deps PATTERN1 [PATTERNn]" | |
category "path-based" | |
deps do | |
require 'chef/chef_fs/file_system' | |
require 'chef/run_list' | |
end | |
option :recurse, | |
:long => '--[no-]recurse', | |
:boolean => true, | |
:description => "List dependencies recursively (default: true). Only works with --tree." | |
option :tree, | |
:long => '--tree', | |
:boolean => true, | |
:description => "Show dependencies in a visual tree. May show duplicates." | |
option :remote, | |
:long => '--remote', | |
:boolean => true, | |
:description => "List dependencies on the server instead of the local filesystem" | |
attr_accessor :exit_code | |
def run | |
if config[:recurse] == false && !config[:tree] | |
ui.error "--no-recurse requires --tree" | |
exit(1) | |
end | |
config[:recurse] = true if config[:recurse].nil? | |
@root = config[:remote] ? chef_fs : local_fs | |
dependencies = {} | |
pattern_args.each do |pattern| | |
Chef::ChefFS::FileSystem.list(@root, pattern).each do |entry| | |
if config[:tree] | |
print_dependencies_tree(entry, dependencies) | |
else | |
print_flattened_dependencies(entry, dependencies) | |
end | |
end | |
end | |
exit exit_code if exit_code | |
end | |
def print_flattened_dependencies(entry, dependencies) | |
if !dependencies[entry.path] | |
dependencies[entry.path] = get_dependencies(entry) | |
dependencies[entry.path].each do |child| | |
child_entry = Chef::ChefFS::FileSystem.resolve_path(@root, child) | |
print_flattened_dependencies(child_entry, dependencies) | |
end | |
output "#{entry.chef_object.metadata.name} (#{entry.chef_object.metadata.version})" #bjbishop hack | |
end | |
end | |
def print_dependencies_tree(entry, dependencies, printed = {}, depth = 0) | |
dependencies[entry.path] = get_dependencies(entry) if !dependencies[entry.path] | |
output "#{' '*depth}#{entry.chef_object.metadata.name} (#{entry.chef_object.metadata.version})" #bjbishop hack | |
if !printed[entry.path] && (config[:recurse] || depth == 0) | |
printed[entry.path] = true | |
dependencies[entry.path].each do |child| | |
child_entry = Chef::ChefFS::FileSystem.resolve_path(@root, child) | |
print_dependencies_tree(child_entry, dependencies, printed, depth+1) | |
end | |
end | |
end | |
def get_dependencies(entry) | |
begin | |
if entry.parent && entry.parent.path == '/cookbooks' | |
return entry.chef_object.metadata.dependencies.keys.map { |cookbook| "/cookbooks/#{cookbook}" } | |
elsif entry.parent && entry.parent.path == '/nodes' | |
node = JSON.parse(entry.read, :create_additions => false) | |
result = [] | |
if node['chef_environment'] && node['chef_environment'] != '_default' | |
result << "/environments/#{node['chef_environment']}.json" | |
end | |
if node['run_list'] | |
result += dependencies_from_runlist(node['run_list']) | |
end | |
result | |
elsif entry.parent && entry.parent.path == '/roles' | |
role = JSON.parse(entry.read, :create_additions => false) | |
result = [] | |
if role['run_list'] | |
dependencies_from_runlist(role['run_list']).each do |dependency| | |
result << dependency if !result.include?(dependency) | |
end | |
end | |
if role['env_run_lists'] | |
role['env_run_lists'].each_pair do |env, run_list| | |
dependencies_from_runlist(run_list).each do |dependency| | |
result << dependency if !result.include?(dependency) | |
end | |
end | |
end | |
result | |
elsif !entry.exists? | |
raise Chef::ChefFS::FileSystem::NotFoundError.new(entry) | |
else | |
[] | |
end | |
rescue Chef::ChefFS::FileSystem::NotFoundError => e | |
ui.error "#{format_path(e.entry)}: No such file or directory" | |
self.exit_code = 2 | |
[] | |
end | |
end | |
def dependencies_from_runlist(run_list) | |
chef_run_list = Chef::RunList.new | |
chef_run_list.reset!(run_list) | |
chef_run_list.map do |run_list_item| | |
case run_list_item.type | |
when :role | |
"/roles/#{run_list_item.name}.json" | |
when :recipe | |
if run_list_item.name =~ /(.+)::[^:]*/ | |
"/cookbooks/#{$1}" | |
else | |
"/cookbooks/#{run_list_item.name}" | |
end | |
else | |
raise "Unknown run list item type #{run_list_item.type}" | |
end | |
end | |
end | |
end | |
end | |
end |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment