Skip to content

Commit

Permalink
Actually, implement a custom type and provider, without relying on pu…
Browse files Browse the repository at this point in the history
…ppet's gem. Lost 3 hours because of a missing require. Rails' autoloading has made me dumb.
  • Loading branch information
vjt authored and System Administrator (on puppet.ifad.org) committed Jul 30, 2012
1 parent e90285d commit 7995e3b
Show file tree
Hide file tree
Showing 3 changed files with 105 additions and 30 deletions.
58 changes: 32 additions & 26 deletions lib/puppet/provider/rbenvgem.rb
Original file line number Diff line number Diff line change
@@ -1,41 +1,47 @@
require 'puppet/provider/package/gem'

# This provider extends the original Gem one, and hacks the "gemcmd" command
# by adding the prefix passed to the resource into the "root" parameter.
#
Puppet::Type.type(:package).provide :rbenvgem, :parent => :gem do
Puppet::Type.type(:rbenvgem).provide :default do
desc "Maintains gems inside an RBenv setup"

commands :gemcmd => 'gem'
commands :su => 'su'

def install
args = ['install', '--no-rdoc', '--no-ri']
args << "-v#{resource[:ensure]}" if !resource[:ensure].kind_of?(Symbol)
args << gem_name

# This provider should never be called by default.
def self.specificity
-0xff
output = gem(*args)
fail "Could not install: #{output.chomp}" if output.include?('ERROR')
end

def gemcmd(*args)
args.shift
args.unshift(scoped_gem)
def uninstall
gem 'uninstall', '-aIx', gem_name
end

super(*args)
def latest
@latest ||= list(:remote)
end

def command(*args)
return super unless args.first == :gemcmd
scoped_gem
def current
list
end

def execute(command)
if command.last =~ / :: /
gem = command.pop
command.push gem.split(' :: ').last
private
def gem_name
resource[:gemname]
end

super
end
def gem(*args)
exe = resource[:rbenv] + '/bin/gem'
su('-', resource[:user], '-c', [exe, *args].join(' '))
end

private
def scoped_gem
resource[:root] + '/bin/gem'
def list(where = :local)
args = ['list', where == :remote ? '--remote' : '--local', "#{gem_name}$"]

gem(*args).lines.map do |line|
line =~ /^(?:\S+)\s+\((.+)\)/

ver = $1.split(/,\s*/)
ver.empty? ? nil : ver
end.first
end
end
68 changes: 68 additions & 0 deletions lib/puppet/type/rbenvgem.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,68 @@
require 'puppet/provider/rbenvgem' # Do not EVER forget the require when developing puppet types. -vjt

Puppet.newtype(:rbenvgem) do
@doc = "An RBenv gem"

ensurable do
newvalue(:present) { provider.install }
newvalue(:absent ) { provider.uninstall }

newvalue(:latest) {
provider.uninstall if provider.current
provider.install
}

newvalue(/./) do
provider.uninstall if provider.current
provider.install
end

aliasvalue :installed, :present

defaultto :present

def retrieve
provider.current || :absent
end

def insync?(current)
requested = @should.first

# puts "current: #{current.inspect}"
# puts "reqd : #{requested.inspect}"
# puts "latest : #{[provider.latest.inspect]}"

ret = case requested
when :present, :installed
current != :absent
when :latest
current == provider.latest
when :absent
current == :absent
else
current == [requested]
end

# puts "ret: #{ret}"

return ret
end
end

newparam(:name) do
desc 'Gem qualified name within an rbenv repository'
end

newparam(:gemname) do
desc 'The Gem name'
end

newparam(:rbenv) do
desc 'The rbenv root'
end

newparam(:user) do
desc 'The rbenv owner'
end

end
9 changes: 5 additions & 4 deletions manifests/gem.pp
Original file line number Diff line number Diff line change
Expand Up @@ -14,9 +14,10 @@
fail("Rbenv-Ruby ${ruby} for user ${user} not found in catalog")
}

package {"rbenv::${user}/${ruby} :: ${gem}":
ensure => $ensure,
provider => 'rbenvgem',
root => "${root}/versions/${ruby}"
rbenvgem {"${user}/${ruby}/${gem}":
ensure => $ensure,
user => $user,
gemname => $gem,
rbenv => "${root}/versions/${ruby}"
}
}

0 comments on commit 7995e3b

Please sign in to comment.