lib/backup/dependency.rb in backup-3.0.27 vs lib/backup/dependency.rb in backup-3.1.0

- old
+ new

@@ -1,108 +1,159 @@ # encoding: utf-8 module Backup - ## # A little self-contained gem manager for Backup. - # Rather than specifying hard dependencies in the gemspec, forcing users - # to install gems they do not want/need, Backup will notify them when a gem - # has not been installed, or when the gem's version is incorrect, and provide the - # command to install the gem. These dependencies are dynamically loaded in the Gemfile + # Rather than specifying hard dependencies in the gemspec, forcing users to + # install gems they do not want/need, Backup will notify them when a gem has + # not been installed, or version is incorrect, and provide the command to + # install the gem. These dependencies are dynamically loaded in the Gemfile. class Dependency + DEPENDENCIES = { + 'fog' => { + :require => 'fog', + :version => '~> 1.4', + :for => 'Amazon S3, Rackspace Cloud Files (S3, CloudFiles Storages)', + :dependencies => ['net-ssh', 'net-scp'] + }, - ## - # Returns a hash of dependencies that Backup requires - # in order to run every available feature - def self.all - { - 'fog' => { - :require => 'fog', - :version => '~> 1.4.0', - :for => 'Amazon S3, Rackspace Cloud Files (S3, CloudFiles Storages)' - }, + 'dropbox-sdk' => { + :require => 'dropbox_sdk', + :version => '~> 1.5.0', + :for => 'Dropbox Web Service (Dropbox Storage)' + }, - 'dropbox-sdk' => { - :require => 'dropbox_sdk', - :version => '~> 1.2.0', - :for => 'Dropbox Web Service (Dropbox Storage)' - }, + 'net-sftp' => { + :require => 'net/sftp', + :version => ['>= 2.0.0', '<= 2.0.5'], + :for => 'SFTP Protocol (SFTP Storage)', + :dependencies => 'net-ssh' + }, - 'net-sftp' => { - :require => 'net/sftp', - :version => '~> 2.0.5', - :for => 'SFTP Protocol (SFTP Storage)' - }, + 'net-scp' => { + :require => 'net/scp', + :version => ['>= 1.0.0', '<= 1.0.4'], + :for => 'SCP Protocol (SCP Storage)', + :dependencies => 'net-ssh' + }, - 'net-scp' => { - :require => 'net/scp', - :version => '~> 1.0.4', - :for => 'SCP Protocol (SCP Storage)' - }, + 'net-ssh' => { + :require => 'net/ssh', + :version => ['>= 2.3.0', '<= 2.5.2'], + :for => 'SSH Protocol (SSH Storage)' + }, - 'net-ssh' => { - :require => 'net/ssh', - :version => '~> 2.3.0', - :for => 'SSH Protocol (SSH Storage)' - }, + 'mail' => { + :require => 'mail', + :version => '~> 2.5.0', + :for => 'Sending Emails (Mail Notifier)' + }, - 'mail' => { - :require => 'mail', - :version => '~> 2.4.0', - :for => 'Sending Emails (Mail Notifier)' - }, + 'twitter' => { + :require => 'twitter', + :version => '~> 4.0', + :for => 'Sending Twitter Updates (Twitter Notifier)' + }, - 'twitter' => { - :require => 'twitter', - :version => '>= 1.7.1', - :for => 'Sending Twitter Updates (Twitter Notifier)' - }, + 'httparty' => { + :require => 'httparty', + :version => '~> 0.10.2', + :for => 'Sending Http Updates (Campfire Notifier)' + }, - 'httparty' => { - :require => 'httparty', - :version => '~> 0.8.1', - :for => 'Sending Http Updates' - }, + 'prowler' => { + :require => 'prowler', + :version => '~> 1.3.1', + :for => 'Sending iOS push notifications (Prowl Notifier)' + }, - 'prowler' => { - :require => 'prowler', - :version => '>= 1.3.1', - :for => 'Sending iOS push notifications (Prowl Notifier)' - }, + 'hipchat' => { + :require => 'hipchat', + :version => '~> 0.7.0', + :for => 'Sending notifications to Hipchat' + }, - 'hipchat' => { - :require => 'hipchat', - :version => '~> 0.4.1', - :for => 'Sending notifications to Hipchat' - }, - - 'parallel' => { - :require => 'parallel', - :version => '~> 0.5.12', - :for => 'Adding concurrency to Cloud-based syncers.' - } + 'parallel' => { + :require => 'parallel', + :version => '~> 0.6.0', + :for => 'Adding concurrency to Cloud-based syncers.' } + } + + class << self + def all + @all ||= [] + end + + def find(name) + all.select {|dep| dep.name == name }.first + end + + def load(name) + find(name).load! + end end - ## - # Attempts to load the specified gem (by name and version). - # If the gem with the correct version cannot be found, it'll display a message - # to the user with instructions on how to install the required gem - def self.load(name) - begin - gem(name, all[name][:version]) - require(all[name][:require]) - rescue LoadError - Logger.error Errors::Dependency::LoadError.new(<<-EOS) - Dependency missing - Dependency required for: - #{all[name][:for]} - To install the gem, issue the following command: - > gem install #{name} -v '#{all[name][:version]}' - Please try again after installing the missing dependency. - EOS - exit 1 + attr_reader :name, :require_as, :used_for, :requirements + + def initialize(name, options = {}) + @name = name + @require_as = options[:require] + @requirements = Array(options[:version]) + @dependencies = Array(options[:dependencies]) + @used_for = options[:for] + end + + # dependencies should be defined in the order + # they should be installed or loaded. + def dependencies + @dependencies.map {|name| self.class.find(name) } + end + + def load! + dependencies.each(&:load!) + + gem(name, *requirements) + require require_as + rescue LoadError + raise Errors::Dependency::LoadError, <<-EOS + Dependency Missing + Gem Name: #{ name } + Used for: #{ used_for } + + To install the gem, issue the following command: + > backup dependencies --install #{ name } + Please try again after installing the missing dependency. + EOS + end + + def installed? + Gem::Specification.find_by_name(name, *requirements) + true + rescue LoadError + false + end + + # If multiple version requirements are defined, this tries to find the + # version that matches them all. Otherwise, it will fallback to installing + # based on the last requirement. This should only be called from the CLI + # for `backup dependencies --install <name>`. + def install! + version = nil + if requirements.count > 1 + begin + require 'rubygems/dependency_installer' + inst = Gem::DependencyInstaller.new + spec, _ = inst.find_spec_by_name_and_version(name, *requirements).first + version = spec.version + rescue + end end + version ||= requirements.last + command = "gem install --no-ri --no-rdoc #{ name } -v '#{ version }'" + puts "\nLaunching `#{ command }`" + exec command end + DEPENDENCIES.each {|name, options| all << new(name, options) } end end