summaryrefslogtreecommitdiffstats
path: root/lib/puppet/provider/package/gem.rb
blob: 8d70b756f6d3a95025e791aa0df991cc1c99c10f (plain)
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
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."

  has_feature :versionable

  commands :gemcmd => "gem"

  def self.gemlist(hash)
    command = [command(:gemcmd), "list"]

    if hash[:local]
      command << "--local"
    else
      command << "--remote"
    end

    if name = hash[:justme]
      command << name
    end

    begin
      list = execute(command).split("\n").collect do |set|
        if gemhash = gemsplit(set)
          gemhash[:provider] = :gem
          gemhash
        else
          nil
        end
      end.compact
    rescue Puppet::ExecutionFailure => detail
      raise Puppet::Error, "Could not list gems: #{detail}"
    end

    if hash[:justme]
      return list.shift
    else
      return list
    end
  end

  def self.gemsplit(desc)
    case desc
    when /^\*\*\*/, /^\s*$/, /^\s+/; return nil
    when /^(\S+)\s+\((.+)\)/
      name = $1
      version = $2.split(/,\s*/)[0]
      return {
        :name => name,
        :ensure => version
      }
    else
      Puppet.warning "Could not match #{desc}"
      nil
    end
  end

  def self.instances(justme = false)
    gemlist(:local => true).collect do |hash|
      new(hash)
    end
  end

  def install(useversion = true)
    command = [command(:gemcmd), "install"]
    command << "-v" << resource[:ensure] if (! resource[:ensure].is_a? Symbol) and useversion
    # Always include dependencies
    command << "--include-dependencies"

    if source = resource[:source]
      begin
        uri = URI.parse(source)
      rescue => detail
        fail "Invalid source '#{uri}': #{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
        # interpret it as a gem repository
        command << "--source" << "#{source}" << resource[:name]
      end
    else
      command << resource[:name]
    end

    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.
    hash = self.class.gemlist(:justme => resource[:name])

    hash[:ensure]
  end

  def query
    self.class.gemlist(:justme => resource[:name], :local => true)
  end

  def uninstall
    gemcmd "uninstall", "-x", "-a", resource[:name]
  end

  def update
    self.install(false)
  end
end