在没有子shell的情况下动态列出cookbook

时间:2013-08-07 13:02:55

标签: ruby chef

我可以通过在子shell中调用knife来检索cookbook列表(然后解析输出),例如:

cb = `knife cookbook list`

另一种方法是直接调用ruby类/模块,例如:

require("chef")
require("chef/knife")
Chef::Config.from_file(knifePath) #knifePath is declared a priori
cookbooks = Chef::Knife.run(["cookbook", "list"])
puts(cookbooks) # => nil

如何通过将Chef::Knife.run()调用到变量中来存储打印在屏幕上的数据?

1 个答案:

答案 0 :(得分:0)

你需要在knife之外寻找这个。 Knife委托给Chef::CookbookLoader(在堆栈下面),因此你可以直接使用cookbook loader:

require 'chef/config'
require 'chef/cookbook_loader'

Chef::Config.from_file(path)
cookbooks = Chef::CookbookLoader.new(Chef::Config.cookbook_path).map(&:cookbook_name)

例如,knife-spork使用此模式加载cookbook。

请注意,您将获得实际的cookbook对象,而不仅仅是他们的名字。如果你想要一些更轻量级的东西,你可以迭代每个cookbook_path并寻找metadata.rb

# https://gist.github.com/fnichol/4343327
class MetadataChopper < Hash 
  def self.extract(metadata_file)
    mc = new(File.expand_path(metadata_file))
    [mc[:name], mc[:version]]
  end

  def initialize(metadata_file)
    eval(IO.read(metadata_file), nil, metadata_file)
  end

  def method_missing(meth, *args, &block)
    self[meth] = args.first
  end
end

require 'chef/config'
cookbook_paths = Chef::Config.from_file(path).cookbook_path

cookbooks = Dir[*cookbook_paths.map { |p| "#{p}/**/metadata.rb" }].collect do |metadata|
  MetadataChopper.new(metadata)[:name] || File.basename(File.dirname(cookbook))
end