class AutomateIt::PackageManager::Gem

PackageManager::Gem

The Gem driver for the PackageManager provides a way to manage software packages for RubyGems using the gem command.

Specifying version of gem to use

You can specify the command to use with each call using the gem option, e.g., the “gem1.8” below:

package_manager.install 'rails', :with => :gem, :gem => "gem1.8"

Or set a default and all subsequent calls will use it:

package_manager[:gem].setup(:gem => "gem1.8")
package_manager.install 'rails', :with => :gem

Attributes

gem[RW]

Public Instance Methods

install(*packages) click to toggle source

Special options:

  • :docs – If set to false, won’t install rdoc or ri.

  • :source – URL source to retrieve Gems from.

See PackageManager#install

# File lib/automateit/package_manager/gem.rb, line 71
def install(*packages)
  return _install_helper(*packages) do |list, opts|
    gem = opts[:gem] || self.gem

    # Why is the "gem" utility such a steaming pile of offal? Lameness include:
    # - Requires interactive input to install a package, with no way to prevent this
    # - Repeatedly updates indexes even when there's no reason to, and can't be told to stop
    # - Doesn't cache packages, insists on downloading them again
    # - Installs broken packages, often without giving any indication of failure
    # - Installs broken packages and leaves you to deal with the jagged pieces
    # - Sometimes fails through exit status, sometimes through output, but not both and not consistently
    # - Lacks a proper "is this package installed?" feature
    # - A nightmare to deal with if you want to install your own GEMHOME/GEMPATH

    # Example of an invalid gem that'll cause the failure I'm trying to avoid below:
    #   package_manager.install("sys-cpu", :with => :gem)

    # gem options:
    # -y : Include dependencies,
    # -E : use /usr/bin/env for installed executables; but only with >= 0.9.4
    cmd = "#{gem} install -y"
    cmd << " --no-ri" if opts[:ri] == false or opts[:docs] == false
    cmd << " --no-rdoc" if opts[:rdoc] == false or opts[:docs] == false
    cmd << " --source #{opts[:source]}" if opts[:source]
    cmd << " "+list.join(" ")
    cmd << " " << opts[:args] if opts[:args]
    cmd << " 2>&1"

    # XXX Try to warn the user that they won't see any output for a while
    log.info(PNOTE+"Installing Gems, this will take a while...") if writing? and not opts[:quiet]
    log.info(PEXEC+cmd)
    return true if preview?

    uninstall_needed = false
    begin
      require 'expect'
      require 'open4'
      exitstruct = Open4::popen4(cmd) do |pid, sin, sout, serr|
        $expect_verbose = opts[:quiet] ? false : true

        re_missing=/Could not find.+in any repository/m
        re_select=/Select which gem to install.+>/m
        re_failed=/Gem files will remain.+for inspection/m
        re_refused=/Errno::ECONNREFUSED reading .+?\.gem/m
        re_all=/#{re_missing}|#{re_select}|#{re_failed}|#{re_refused}/m

        while true
          begin
            captureded = sout.expect(re_all)
          rescue NoMethodError
            log.debug(PNOTE+"Gem seems to be done")
            break
          end
          ### puts "Captureded %s" % captureded.inspect
          captured = captureded.first
          if captured.match(re_failed)
            log.warn(PERROR+"Gem install failed mid-process")
            uninstall_needed = true
            break
          elsif captured.match(re_refused)
            log.warn(PERROR+"Gem install refused by server!\n#{captured}")
            break
          elsif captured.match(re_select)
            choice = captured.match(/^ (\d+)\. .+?\(ruby\)\s*$/)[1]
            log.info(PNOTE+"Guessing: #{choice}")
            sin.puts(choice)
          end
        end
      end
    rescue Errno::ENOENT => e
      raise NotImplementedError.new("can't find gem command: #{e}")
    end

    if uninstall_needed or not exitstruct.exitstatus.zero?
      log.error(PERROR+"Gem install failed, trying to uninstall broken pieces: #{list.inspect}")
      uninstall(list, opts)

      raise ArgumentError.new("Gem install failed because it's invalid, missing a dependency, or can't talk with Gem server: #{list.inspect}")
    end
  end
end
installed?(*packages) click to toggle source

See PackageManager#installed?

# File lib/automateit/package_manager/gem.rb, line 41
def installed?(*packages)
  return _installed_helper?(*packages) do |list, opts|
    gem = opts[:gem] || self.gem
    cmd = "#{gem} list --local 2>&1"

    log.debug(PEXEC+cmd)
    data = `#{cmd}`

    # Gem lists packages out of order, which screws up the
    # install/uninstall sequence, so we need to put them back in the
    # order that the user specified.
    present = data.scan(/^([^\s\(]+)\s+\([^\)]+\)\s*$/).flatten
    available = []
    for package in list
      available << package if present.include?(package)
    end
    available
  end
end
not_installed?(*packages) click to toggle source

See PackageManager#not_installed?

# File lib/automateit/package_manager/gem.rb, line 62
def not_installed?(*packages)
  _not_installed_helper?(*packages)
end
setup(*args) click to toggle source

:programs => %w(gem),

Calls superclass method AutomateIt::Plugin::Driver#setup
# File lib/automateit/package_manager/gem.rb, line 24
def setup(*args)
  super(*args)

  args, opts = args_and_opts(*args)
  if opts[:gem]
    @gem = opts[:gem]
  else
    @gem ||= %w(gem gem1.8 gem1.9).inject(nil){|s,v| s ? s : interpreter.which(v)}
  end
end
uninstall(*packages) click to toggle source

See PackageManager#uninstall

# File lib/automateit/package_manager/gem.rb, line 154
  def uninstall(*packages)
    return _uninstall_helper(*packages) do |list, opts|
      gem = opts[:gem] || self.gem

      # TODO PackageManager::gem#uninstall -- add logic to handle prompts during removal
=begin
# idiotic program MAY prompt you like this on uninstall:

Gem 0.9.4 generates prompts like this:
** gem uninstall -x mongrel < /dev/null 2>&1

You have requested to uninstall the gem:
    mongrel-1.0.1
mongrel_cluster-1.0.2 depends on [mongrel (>= 1.0.1)]
If you remove this gems, one or more dependencies will not be met.
Continue with Uninstall? [Yn]  Successfully uninstalled mongrel version 1.0.1
Removing mongrel_rails

#-----------------------------------------------------------------------
Gem 0.9.0 generates prompts like this:
** gem uninstall -x mongrel < /dev/null 2>&1

Select RubyGem to uninstall:
1. mongrel-1.0.1
2. mongrel_cluster-1.0.2
3. All versions
> 3

You have requested to uninstall the gem:
    mongrel-1.0.1
mongrel_cluster-1.0.2 depends on [mongrel (>= 1.0.1)]
If you remove this gems, one or more dependencies will not be met.
Continue with Uninstall? [Yn]  y
Successfully uninstalled mongrel version 1.0.1
Successfully uninstalled mongrel_cluster version 1.0.2
root@ubuntu:/mnt/satori/svnwork/automateit/src/examples/myapp_rails#
=end
      for package in list
        # gem options:
        # -x : remove installed executables
        cmd = "#{gem} uninstall -x #{package} < /dev/null"
        cmd << " > /dev/null" if opts[:quiet]
        cmd << " 2>&1"
        interpreter.sh(cmd)
      end
    end
  end