Index: Manifest.txt =================================================================== --- Manifest.txt (revision 1126) +++ Manifest.txt (working copy) @@ -37,6 +37,7 @@ lib/geminstaller/missing_dependency_finder.rb lib/geminstaller/missing_file_error.rb lib/geminstaller/noninteractive_chooser.rb +lib/geminstaller/outdated_gem_finder.rb lib/geminstaller/output_filter.rb lib/geminstaller/output_listener.rb lib/geminstaller/output_observer.rb Index: spec/unit/application_spec.rb =================================================================== --- spec/unit/application_spec.rb (revision 1126) +++ spec/unit/application_spec.rb (working copy) @@ -175,6 +175,29 @@ end end +describe "an application instance invoked with print-outdated-gems arg" do + before(:each) do + application_spec_setup_common + @mock_arg_parser.should_receive(:parse).with(nil) + @mock_arg_parser.should_receive(:output).and_return(nil) + @options[:print_outdated_gems] = true + end + + it "should invoke outdated_gem_finder" do + + @mock_config_builder.should_receive(:build_config).and_return {@stub_config_local} + + gems = [@stub_gem] + @stub_config.should_receive(:gems).and_return(gems) + + paths = [] + @mock_config_builder.should_receive(:config_file_paths_array).once.and_return(paths) + @mock_outdated_gem_finder.should_receive(:print_outdated_gems).once().with(gems, paths) + + @application.install + end +end + def application_spec_setup_common @mock_arg_parser = mock("Mock Arg Parser") @mock_config_builder = mock("Mock Config Builder") @@ -183,6 +206,7 @@ @mock_output_filter = mock("Mock Output Filter") @stub_gem = GemInstaller::RubyGem.new("gemname", :version => "1.0") @mock_rogue_gem_finder = mock("Mock RogueGemFinder") + @mock_outdated_gem_finder = mock("Mock OutdatedGemFinder") @options = {} @stub_config_local = @stub_config @@ -194,6 +218,7 @@ @application.install_processor = @mock_install_processor @application.output_filter = @mock_output_filter @application.rogue_gem_finder = @mock_rogue_gem_finder + @application.outdated_gem_finder = @mock_outdated_gem_finder end Index: spec/unit/arg_parser_spec.rb =================================================================== --- spec/unit/arg_parser_spec.rb (revision 1126) +++ spec/unit/arg_parser_spec.rb (working copy) @@ -184,6 +184,24 @@ end end +describe "an ArgParser instance with outdated-gems option" do + before(:each) do + common_setup + end + + it "specified by --outdated-gems should return outdated_gems flag as true in options hash" do + @args.push("--print-outdated-gems") + @arg_parser.parse(@args) + @options[:print_outdated_gems].should==(true) + end + + it "specified by -o should return outdated_gems flag as true in options hash" do + @args.push("-o") + @arg_parser.parse(@args) + @options[:print_outdated_gems].should==(true) + end +end + describe "an ArgParser instance with version option" do before(:each) do common_setup Index: spec/unit/outdated_gem_finder_spec.rb =================================================================== --- spec/unit/outdated_gem_finder_spec.rb (revision 0) +++ spec/unit/outdated_gem_finder_spec.rb (revision 0) @@ -0,0 +1,63 @@ +dir = File.dirname(__FILE__) +require File.expand_path("#{dir}/../helper/spec_helper") + +describe GemInstaller::OutdatedGemFinder do + describe "#print_outdated_gems" do + attr_reader :outdated_gem_finder, :mock_gem_spec_manager, :mock_output_proxy + attr_reader :config_gem, :newer_local_gem + before(:each) do + @outdated_gem_finder = GemInstaller::OutdatedGemFinder.new + @mock_gem_spec_manager = mock("Mock GemSpecManager") + @mock_output_proxy = mock("Mock OutputProxy") + outdated_gem_finder.gem_spec_manager = mock_gem_spec_manager + outdated_gem_finder.output_proxy = mock_output_proxy + + @config_gem = GemInstaller::RubyGem.new('legit', :version => '1.0.0') + @newer_local_gem = GemInstaller::RubyGem.new('legit', :version => '2.0.0') + end + + context "when there are local gems newer than the specification" do + it "prints the outdated gems" do + mock_gem_spec_manager.should_receive(:all_local_gems).and_return([config_gem, newer_local_gem]) + + outdated_gem_text = / - legit 2.0.0/m + mock_output_proxy.should_receive(:sysout).with(outdated_gem_text) + + config_file_paths = [] + output = outdated_gem_finder.print_outdated_gems([config_gem], config_file_paths) + + output.should match(outdated_gem_text) + end + end + + context "when all local gems match the specification" do + attr_reader :broader_gem_version, :no_gems_outdated_message + before do + @broader_gem_version = GemInstaller::RubyGem.new('legit', :version => ">= 1.0.0") + @no_gems_outdated_message = /No outdated gems were found in the geminstaller configuration/m + end + + it "should print message if no local gems have been updated" do + mock_gem_spec_manager.should_receive(:all_local_gems).and_return([config_gem]) + + mock_output_proxy.should_receive(:sysout).with(no_gems_outdated_message) + + config_file_paths = [] + output = outdated_gem_finder.print_outdated_gems([config_gem], config_file_paths) + + output.should match(no_gems_outdated_message) + end + + it "should ignore newer gems if they still satisfy the config requirement" do + mock_gem_spec_manager.should_receive(:all_local_gems).and_return([config_gem, newer_local_gem]) + + @mock_output_proxy.should_receive(:sysout).with(no_gems_outdated_message) + + config_file_paths = [] + output = outdated_gem_finder.print_outdated_gems([broader_gem_version], config_file_paths) + + output.should match(no_gems_outdated_message) + end + end + end +end Index: lib/geminstaller/arg_parser.rb =================================================================== --- lib/geminstaller/arg_parser.rb (revision 1126) +++ lib/geminstaller/arg_parser.rb (working copy) @@ -45,6 +45,8 @@ " - debug: print debug messages\n" + " - all: print all messages" help_msg = "Show this message." + print_outdated_gems_msg = "Print a report of all locally installed gems which have a later\n" + + " version installed than is specified in the geminstaller config file." print_rogue_gems_msg = "Print a report of all locally installed gems which are not specified\n" + " in the geminstaller config file." rubygems_output_msg = "Comma-delimited list of output types to show from internal:\n" + @@ -61,7 +63,7 @@ sudo_msg = "Perform all gem operations under sudo (as root). Will only work on\n" + " correctly configured, supported systems. See docs for more info." silent_msg = "Suppress all output except fatal exceptions, and output from\n" + - " rogue-gems option." + " rogue-gems and outdated-gems options." version_msg = "Show GemInstaller version and exit." opts.on("-cCONFIGPATHS", "--config=CONFIGPATHS", String, config_msg) do |config_paths| @@ -84,6 +86,10 @@ @output = opts.to_s end + opts.on("-o", "--print-outdated-gems", print_outdated_gems_msg) do + @options[:print_outdated_gems] = true + end + opts.on("-p", "--print-rogue-gems", print_rogue_gems_msg) do @options[:print_rogue_gems] = true end Index: lib/geminstaller/requires.rb =================================================================== --- lib/geminstaller/requires.rb (revision 1126) +++ lib/geminstaller/requires.rb (working copy) @@ -65,6 +65,7 @@ require File.expand_path("#{dir}/missing_dependency_finder") require File.expand_path("#{dir}/missing_file_error") require File.expand_path("#{dir}/noninteractive_chooser") +require File.expand_path("#{dir}/outdated_gem_finder") require File.expand_path("#{dir}/output_filter") require File.expand_path("#{dir}/output_listener") require File.expand_path("#{dir}/output_observer") Index: lib/geminstaller/application.rb =================================================================== --- lib/geminstaller/application.rb (revision 1126) +++ lib/geminstaller/application.rb (working copy) @@ -1,7 +1,7 @@ module GemInstaller class Application # we have accessors instead of just writers so that we can ensure it is assembled correctly in the dependency injector test - attr_accessor :config_builder, :install_processor, :output_filter, :arg_parser, :args, :options, :rogue_gem_finder + attr_accessor :config_builder, :install_processor, :output_filter, :arg_parser, :args, :options, :rogue_gem_finder, :outdated_gem_finder attr_writer :autogem def initialize @@ -18,6 +18,9 @@ if @options[:print_rogue_gems] @rogue_gem_finder.print_rogue_gems(gems, @config_builder.config_file_paths_array) return 0 + elsif @options[:print_outdated_gems] + @outdated_gem_finder.print_outdated_gems(gems, @config_builder.config_file_paths_array) + return 0 end if gems.size == 0 message = "No gems found in config file. Try the --print-rogue-gems option to help populate your config file." Index: lib/geminstaller/registry.rb =================================================================== --- lib/geminstaller/registry.rb (revision 1126) +++ lib/geminstaller/registry.rb (working copy) @@ -3,7 +3,7 @@ attr_accessor :file_reader, :yaml_loader, :output_proxy, :config_builder, :gem_source_index, :gem_runner_proxy attr_accessor :gem_runner, :gem_command_manager, :gem_list_checker, :app, :arg_parser, :options attr_accessor :install_processor, :missing_dependency_finder, :valid_platform_selector - attr_accessor :output_listener, :outs_output_observer, :errs_output_observer, :output_filter, :autogem, :rogue_gem_finder + attr_accessor :output_listener, :outs_output_observer, :errs_output_observer, :output_filter, :autogem, :rogue_gem_finder, :outdated_gem_finder attr_accessor :gem_spec_manager, :source_index_search_adapter if GemInstaller::RubyGemsVersionChecker.matches?('<=0.9.4') @@ -82,6 +82,11 @@ @rogue_gem_finder.gem_spec_manager = @gem_spec_manager @rogue_gem_finder.output_proxy = @output_proxy + @outdated_gem_finder = GemInstaller::OutdatedGemFinder.new + @outdated_gem_finder.gem_command_manager = @gem_command_manager + @outdated_gem_finder.gem_spec_manager = @gem_spec_manager + @outdated_gem_finder.output_proxy = @output_proxy + @autogem = GemInstaller::Autogem.new @autogem.gem_command_manager = @gem_command_manager @autogem.gem_source_index_proxy = @gem_source_index_proxy @@ -117,6 +122,7 @@ @app = GemInstaller::Application.new @app.autogem = @autogem @app.rogue_gem_finder = @rogue_gem_finder + @app.outdated_gem_finder = @outdated_gem_finder @app.options = @options @app.arg_parser = @arg_parser @app.config_builder = @config_builder Index: lib/geminstaller/outdated_gem_finder.rb =================================================================== --- lib/geminstaller/outdated_gem_finder.rb (revision 0) +++ lib/geminstaller/outdated_gem_finder.rb (revision 0) @@ -0,0 +1,41 @@ +module GemInstaller + class OutdatedGemFinder + attr_writer :output_proxy, :gem_command_manager, :gem_spec_manager + + def print_outdated_gems(config_gems, config_file_paths) + all_local_gems = @gem_spec_manager.all_local_gems + outdated_gems = [] + + all_local_gems.each do |local_gem| + config_gems.each do |config_gem| + name_matches = config_gem.name == local_gem.name + config_gem_version_requirement = Gem::Version::Requirement.new [config_gem.version] + local_gem_version = Gem::Version.new(local_gem.version) + if (name_matches && !config_gem_version_requirement.satisfied_by?(local_gem_version)) + outdated_gems << local_gem + end + end + end + + handle_output(outdated_gems) + end + + def handle_output(gem_list) + output = [] + if gem_list.nil? || gem_list.empty? + output << "No outdated gems were found in the geminstaller configuration" + else + output << "The following outdated gems were found:" + gem_list.each do |outdated_gem| + output << " - #{outdated_gem.name} #{outdated_gem.version}" + end + output << "" + output << "Update the version numbers in the geminstaller.yml to fix this issue" + end + + output_string = output.join("\n") + @output_proxy.sysout output_string + output_string + end + end +end \ No newline at end of file