diff --git a/plugins/commands/plugin/action.rb b/plugins/commands/plugin/action.rb index 4c171256a..2d0024915 100644 --- a/plugins/commands/plugin/action.rb +++ b/plugins/commands/plugin/action.rb @@ -47,7 +47,6 @@ module VagrantPlugins autoload :LicensePlugin, action_root.join("license_plugin") autoload :ListPlugins, action_root.join("list_plugins") autoload :PluginExistsCheck, action_root.join("plugin_exists_check") - autoload :PruneGems, action_root.join("prune_gems") autoload :UninstallPlugin, action_root.join("uninstall_plugin") end end diff --git a/plugins/commands/plugin/action/prune_gems.rb b/plugins/commands/plugin/action/prune_gems.rb deleted file mode 100644 index d5e754994..000000000 --- a/plugins/commands/plugin/action/prune_gems.rb +++ /dev/null @@ -1,158 +0,0 @@ -require "rubygems" -require "rubygems/user_interaction" -require "rubygems/uninstaller" -require "set" - -require "log4r" - -module VagrantPlugins - module CommandPlugin - module Action - # This class prunes any unnecessary gems from the Vagrant-managed - # gem folder. This keeps the gem folder to the absolute minimum set - # of required gems and doesn't let it blow up out of control. - # - # A high-level description of how this works: - # - # 1. Get the list of installed plugins. Vagrant maintains this - # list on its own. - # 2. Get the list of installed RubyGems. - # 3. Find the latest version of each RubyGem that matches an installed - # plugin. These are our root RubyGems that must be installed. - # 4. Go through each root and mark all dependencies recursively as - # necessary. - # 5. Set subtraction between all gems and necessary gems yields a - # list of gems that aren't needed. Uninstall them. - # - class PruneGems - def initialize(app, env) - @app = app - @logger = Log4r::Logger.new("vagrant::plugins::plugincommand::prune") - end - - def call(env) - @logger.info("Pruning gems...") - - # Get the list of installed plugins according to the state file - installed = env[:plugin_state_file].installed_plugins.keys - - # Get the actual specifications of installed gems - all_specs = env[:gem_helper].with_environment do - [].tap do |result| - Gem::Specification.find_all do |s| - # Ignore default gems since they can't be uninstalled - next if s.respond_to?(:default_gem?) && s.default_gem? - - result << s - end - end - end - - # The list of specs to prune initially starts out as all of them - all_specs = Set.new(all_specs) - - # Go through each spec and find the latest version of the installed - # gems, since we want to keep those. - installed_specs = {} - - @logger.debug("Collecting installed plugin gems...") - all_specs.each do |spec| - # If this isn't a spec that we claim is installed, skip it - next if !installed.include?(spec.name) - - # If it is already in the specs, then we need to make sure we - # have the latest version. - if installed_specs.has_key?(spec.name) - if installed_specs[spec.name].version > spec.version - next - end - end - - @logger.debug(" -- #{spec.name} (#{spec.version})") - installed_specs[spec.name] = spec - end - - # Recursive dependency checker to keep all dependencies and remove - # all non-crucial gems from the prune list. - good_specs = Set.new - to_check = installed_specs.values - - while true - # If we're out of gems to check then we break out - break if to_check.empty? - - # Get a random (first) element to check - spec = to_check.shift - - # If we already checked this, then do the next one - next if good_specs.include?(spec) - - # Find all the dependencies and add the latest compliant gem - # to the `to_check` list. - if spec.dependencies.length > 0 - @logger.debug("Finding dependencies for '#{spec.name}' to mark as good...") - spec.dependencies.each do |dep| - # Ignore non-runtime dependencies - next if dep.type != :runtime - @logger.debug("Searching for: '#{dep.name}'") - - latest_matching = nil - - all_specs.each do |prune_spec| - if dep =~ prune_spec - # If we have a matching one already and this one isn't newer - # then we ditch it. - next if latest_matching && - prune_spec.version <= latest_matching.version - - latest_matching = prune_spec - end - end - - if latest_matching.nil? - @logger.error("Missing dependency for '#{spec.name}': #{dep.name}") - next - end - - @logger.debug("Latest matching dep: '#{latest_matching.name}' (#{latest_matching.version})") - to_check << latest_matching - end - end - - # Add ito the list of checked things so we don't accidentally - # re-check it - good_specs.add(spec) - end - - # Figure out the gems we need to prune - prune_specs = all_specs - good_specs - @logger.debug("Gems to prune: #{prune_specs.inspect}") - @logger.info("Pruning #{prune_specs.length} gems.") - - if prune_specs.length > 0 - env[:gem_helper].with_environment do - # Due to a bug in rubygems 2.0, we need to load the - # specifications before removing any. This achieves that. - Gem::Specification.to_a - - prune_specs.each do |prune_spec| - uninstaller = Gem::Uninstaller.new(prune_spec.name, { - :all => true, - :executables => true, - :force => true, - :ignore => true, - :version => prune_spec.version.version - }) - - @logger.info("Uninstalling: #{prune_spec.name} (#{prune_spec.version})") - uninstaller.uninstall - end - end - end - - @app.call(env) - end - end - end - end -end