ext_conf and its uses with omnibus!
So I’ve mentioned in the past that I was struggling to integrate kitchen-cabinet
with omnibus tools like chef (or chefdk). My old solution was to do this:
def self.chef_check
if File.exist?('/opt/chef')
ENV['GEM_HOME'] = '/opt/chef/embedded/lib/ruby/gems/1.9.1'
elsif File.exist?('C:\opscode\chef\\')
ENV['GEM_HOME'] = 'C:\opscode\chef\embedded\lib\ruby\gems\1.9.1'
elsif Gem::Specification.find_by_name('chef')
ENV['GEM_HOME']
else
puts 'You don\'t appear to have chef installed.'
puts 'Please install the gem or omnibus version - `gem install chef` or http://www.getchef.com/chef/install/'
exit
end
end
Now, this allowed me not to step on any toes, but it did leave a little bit to be desired. If the user didn’t have chef installed, it wouldn’t go ahead and take care of it for them. It also did some strange things the the GEM_HOME
variable in order to check for chef’s existence (and to be able to use it without shelling out).
I’ve gotten a bit more clever about that though, especially since chefdk was released. Now I can check for chefdk, and then install gems in the embedded chefdk ruby! Omnibus chef and chefdk differ in the way they handle gems - chefdk will save user-installed gems in your home directory, while omnibus-chef would keep them in /opt/chef. What this means is that chefdk can be upgraded without losing gems, while omnibus-chef gets wiped out every time!
In addition, instead of checking dependencies at runtime, ext_conf
allows me to install native extensions at the time of gem install
.
Basically, I have a file (`ext/mkrf_conf.rb) that looks like this:
require 'rubygems'
require 'rubygems/command.rb'
require 'rubygems/dependency_installer.rb'
Gem::Command.build_args = ARGV
inst = Gem::DependencyInstaller.new
if File.exist?('/opt/chefdk')
%w(chefspec serverspec guard guard-rubocop guard-foodcritic guard-kitchen guard-rspec rspec).each do |gems|
`chef gem install #{gems}`
end
elsif File.exist?('/opt/chef')
puts 'Consider switching to chefdk or the gem version of chef.'
puts 'Some functionality of kitchen-cabinet may not be unavailable with your current setup.'
%w(foodcritic rubocop test-kitchen kitchen-vagrant chefspec serverspec guard guard-rubocop guard-foodcritic guard-kitchen guard-rspec rspec).each do |gems|
`sudo /opt/chef/embedded/bin/gem install #{gems} --no-ri --no-rdoc`
end
else
inst.install 'chef', '~> 11.12.2'
inst.install 'chefspec', '~> 0.0.0'
end
# create dummy rakefile to indicate success
f = File.open(File.join(File.dirname(__FILE__), 'Rakefile'), 'w')
f.write("task :default\n")
f.close
and in my Gemspec, I reference that like this:
s.extensions = 'ext/mkrf_conf.rb'
Now when kitchen-cabinet is installed, it goes ahead and checks dependencies, and installs things where it should! I’d like to clean things up a bit - maybe check for the chef
command that is part of chefdk instead of the directory, and maybe I could do something similar for omnibus-chef. I’d also like to work on pinning versions for gems that I install, since the newest may not always be what I want!
In the end, this was released in version 3.0 of kitchen-vabinet, and I think it’s a huge improvement. There definitely needs to be more work done with the gemfile, as it’s currently very lacking, but all in all, I’m happy with where it is going.