Class: Chef::Knife::SubcommandLoader

Inherits:
Object
  • Object
show all
Defined in:
lib/chef/knife/core/subcommand_loader.rb

Instance Attribute Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(chef_config_dir, env = ENV) ⇒ SubcommandLoader

Returns a new instance of SubcommandLoader.



28
29
30
31
# File 'lib/chef/knife/core/subcommand_loader.rb', line 28

def initialize(chef_config_dir, env=ENV)
  @chef_config_dir, @env = chef_config_dir, env
  @forced_activate = {}
end

Instance Attribute Details

#chef_config_dirObject (readonly)

Returns the value of attribute chef_config_dir.



25
26
27
# File 'lib/chef/knife/core/subcommand_loader.rb', line 25

def chef_config_dir
  @chef_config_dir
end

#envObject (readonly)

Returns the value of attribute env.



26
27
28
# File 'lib/chef/knife/core/subcommand_loader.rb', line 26

def env
  @env
end

Instance Method Details

#find_subcommands_via_dirglobObject



109
110
111
112
113
114
115
116
117
118
# File 'lib/chef/knife/core/subcommand_loader.rb', line 109

def find_subcommands_via_dirglob
  # The "require paths" of the core knife subcommands bundled with chef
  files = Dir[File.join(Chef::Util::PathHelper.escape_glob(File.expand_path('../../../knife', __FILE__)), '*.rb')]
  subcommand_files = {}
  files.each do |knife_file|
    rel_path = knife_file[/#{CHEF_ROOT}#{Regexp.escape(File::SEPARATOR)}(.*)\.rb/,1]
    subcommand_files[rel_path] = knife_file
  end
  subcommand_files
end

#find_subcommands_via_manifestObject

If the user has created a ~/.chef/plugin_manifest.json file, we’ll use that instead of inspecting the on-system gems to find the plugins. The file format is expected to look like:

{ "plugins": {
    "knife-ec2": {
      "paths": [
        "/home/alice/.rubymanagerthing/gems/knife-ec2-x.y.z/lib/chef/knife/ec2_server_create.rb",
        "/home/alice/.rubymanagerthing/gems/knife-ec2-x.y.z/lib/chef/knife/ec2_server_delete.rb"
      ]
    }
  }
}

Extraneous content in this file is ignored. This intentional so that we can adapt the file format for potential behavior changes to knife in the future.



96
97
98
99
100
101
102
103
104
105
106
107
# File 'lib/chef/knife/core/subcommand_loader.rb', line 96

def find_subcommands_via_manifest
  # Format of subcommand_files is "relative_path" (something you can
  # Kernel.require()) => full_path. The relative path isn't used
  # currently, so we just map full_path => full_path.
  subcommand_files = {}
  plugin_manifest["plugins"].each do |plugin_name, plugin_manifest|
    plugin_manifest["paths"].each do |cmd_path|
      subcommand_files[cmd_path] = cmd_path
    end
  end
  subcommand_files.merge(find_subcommands_via_dirglob)
end

#find_subcommands_via_rubygemsObject



120
121
122
123
124
125
126
127
128
129
# File 'lib/chef/knife/core/subcommand_loader.rb', line 120

def find_subcommands_via_rubygems
  files = find_files_latest_gems 'chef/knife/*.rb'
  subcommand_files = {}
  files.each do |file|
    rel_path = file[/(#{Regexp.escape File.join('chef', 'knife', '')}.*)\.rb/, 1]
    subcommand_files[rel_path] = file
  end

  subcommand_files.merge(find_subcommands_via_dirglob)
end

#gem_and_builtin_subcommandsObject

Returns a Hash of paths to knife commands built-in to chef, or installed via gem. If rubygems is not installed, falls back to globbing the knife directory. The Hash is of the form => “/absolute/path” – Note: the “right” way to load the plugins is to require the relative path, i.e.,

require 'chef/knife/command'

but we’re getting frustrated by bugs at every turn, and it’s slow besides. So subcommand loader has been modified to load the plugins by using Kernel.load with the absolute path.



63
64
65
66
67
68
69
70
71
72
73
# File 'lib/chef/knife/core/subcommand_loader.rb', line 63

def gem_and_builtin_subcommands
  if have_plugin_manifest?
    find_subcommands_via_manifest
  else
    # search all gems for chef/knife/*.rb
    require 'rubygems'
    find_subcommands_via_rubygems
  end
rescue LoadError
  find_subcommands_via_dirglob
end

#have_plugin_manifest?Boolean

Returns:

  • (Boolean)


131
132
133
# File 'lib/chef/knife/core/subcommand_loader.rb', line 131

def have_plugin_manifest?
  ENV["HOME"] && File.exist?(plugin_manifest_path)
end

#load_commandsObject

Load all the sub-commands



34
35
36
37
# File 'lib/chef/knife/core/subcommand_loader.rb', line 34

def load_commands
  subcommand_files.each { |subcommand| Kernel.load subcommand }
  true
end

#plugin_manifestObject



135
136
137
# File 'lib/chef/knife/core/subcommand_loader.rb', line 135

def plugin_manifest
  Chef::JSONCompat.from_json(File.read(plugin_manifest_path))
end

#plugin_manifest_pathObject



139
140
141
# File 'lib/chef/knife/core/subcommand_loader.rb', line 139

def plugin_manifest_path
  File.join(ENV['HOME'], '.chef', 'plugin_manifest.json')
end

#site_subcommandsObject

Returns an Array of paths to knife commands located in chef_config_dir/plugins/knife/ and ~/.chef/plugins/knife/



41
42
43
44
45
46
47
48
49
50
51
52
# File 'lib/chef/knife/core/subcommand_loader.rb', line 41

def site_subcommands
  user_specific_files = []

  if chef_config_dir
    user_specific_files.concat Dir.glob(File.expand_path("plugins/knife/*.rb", Chef::Util::PathHelper.escape_glob(chef_config_dir)))
  end

  # finally search ~/.chef/plugins/knife/*.rb
  user_specific_files.concat Dir.glob(File.join(Chef::Util::PathHelper.escape_glob(env['HOME'], '.chef', 'plugins', 'knife'), '*.rb')) if env['HOME']

  user_specific_files
end

#subcommand_filesObject



75
76
77
# File 'lib/chef/knife/core/subcommand_loader.rb', line 75

def subcommand_files
  @subcommand_files ||= (gem_and_builtin_subcommands.values + site_subcommands).flatten.uniq
end