/
gem.rb
169 lines (139 loc) · 4.86 KB
/
gem.rb
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
require 'puppet/provider/package'
require 'uri'
# Ruby gems support.
Puppet::Type.type(:package).provide :gem, :parent => Puppet::Provider::Package do
desc "Ruby Gem support. If a URL is passed via `source`, then that URL is used as the
remote gem repository; if a source is present but is not a valid URL, it will be
interpreted as the path to a local gem file. If source is not present at all,
the gem will be installed from the default gem repositories.
This provider supports the `install_options` and `uninstall_options` attributes,
which allow command-line flags to be passed to the gem command.
These options should be specified as a string (e.g. '--flag'), a hash (e.g. {'--flag' => 'value'}),
or an array where each element is either a string or a hash."
has_feature :versionable, :install_options, :uninstall_options
commands :gemcmd => "gem"
def self.gemlist(options)
gem_list_command = [command(:gemcmd), "list"]
if options[:local]
gem_list_command << "--local"
else
gem_list_command << "--remote"
end
if options[:source]
gem_list_command << "--source" << options[:source]
end
if name = options[:justme]
gem_list_command << "^" + name + "$"
end
begin
list = execute(gem_list_command).lines.
map {|set| gemsplit(set) }.
reject {|x| x.nil? }
rescue Puppet::ExecutionFailure => detail
raise Puppet::Error, "Could not list gems: #{detail}", detail.backtrace
end
if options[:justme]
return list.shift
else
return list
end
end
def self.gemsplit(desc)
# `gem list` when output console has a line like:
# *** LOCAL GEMS ***
# but when it's not to the console that line
# and all blank lines are stripped
# so we don't need to check for them
if desc =~ /^(\S+)\s+\((.+)\)/
gem_name = $1
versions = $2.split(/,\s*/)
{
:name => gem_name,
:ensure => versions.map{|v| v.split[0]},
:provider => name
}
else
Puppet.warning "Could not match #{desc}" unless desc.chomp.empty?
nil
end
end
def self.instances(justme = false)
gemlist(:local => true).collect do |hash|
new(hash)
end
end
def insync?(is)
return false unless is && is != :absent
begin
dependency = Gem::Dependency.new('', resource[:ensure])
rescue ArgumentError
# Bad requirements will cause an error during gem command invocation, so just return not in sync
return false
end
is = [is] unless is.is_a? Array
# Check if any version matches the dependency
is.any? { |version| dependency.match?('', version) }
end
def install(useversion = true)
command = [command(:gemcmd), "install"]
command << "-v" << resource[:ensure] if (! resource[:ensure].is_a? Symbol) and useversion
if source = resource[:source]
begin
uri = URI.parse(source)
rescue => detail
self.fail Puppet::Error, "Invalid source '#{uri}': #{detail}", detail
end
case uri.scheme
when nil
# no URI scheme => interpret the source as a local file
command << source
when /file/i
command << uri.path
when 'puppet'
# we don't support puppet:// URLs (yet)
raise Puppet::Error.new("puppet:// URLs are not supported as gem sources")
else
# check whether it's an absolute file path to help Windows out
if Puppet::Util.absolute_path?(source)
command << source
else
# interpret it as a gem repository
command << "--source" << "#{source}" << resource[:name]
end
end
else
command << "--no-rdoc" << "--no-ri" << resource[:name]
end
command += install_options if resource[:install_options]
output = execute(command)
# Apparently some stupid gem versions don't exit non-0 on failure
self.fail "Could not install: #{output.chomp}" if output.include?("ERROR")
end
def latest
# This always gets the latest version available.
gemlist_options = {:justme => resource[:name]}
gemlist_options.merge!({:source => resource[:source]}) unless resource[:source].nil?
hash = self.class.gemlist(gemlist_options)
hash[:ensure][0]
end
def query
self.class.gemlist(:justme => resource[:name], :local => true)
end
def uninstall
command = [command(:gemcmd), "uninstall"]
command << "--executables" << "--all" << resource[:name]
command += uninstall_options if resource[:uninstall_options]
output = execute(command)
# Apparently some stupid gem versions don't exit non-0 on failure
self.fail "Could not uninstall: #{output.chomp}" if output.include?("ERROR")
end
def update
self.install(false)
end
def install_options
join_options(resource[:install_options])
end
def uninstall_options
join_options(resource[:uninstall_options])
end
end