geminstaller 0.2.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (63) hide show
  1. data/COPYING +1 -0
  2. data/History.txt +4 -0
  3. data/LICENSE +21 -0
  4. data/Manifest.txt +62 -0
  5. data/README.txt +60 -0
  6. data/Rakefile +92 -0
  7. data/TODO.txt +88 -0
  8. data/bin/geminstaller +30 -0
  9. data/geminstaller.yml +34 -0
  10. data/lib/geminstaller/application.rb +105 -0
  11. data/lib/geminstaller/arg_parser.rb +162 -0
  12. data/lib/geminstaller/autogem.rb +43 -0
  13. data/lib/geminstaller/config.rb +69 -0
  14. data/lib/geminstaller/config_builder.rb +40 -0
  15. data/lib/geminstaller/dependency_injector.rb +129 -0
  16. data/lib/geminstaller/enhanced_stream_ui.rb +57 -0
  17. data/lib/geminstaller/exact_match_list_command.rb +16 -0
  18. data/lib/geminstaller/file_reader.rb +31 -0
  19. data/lib/geminstaller/gem_arg_processor.rb +44 -0
  20. data/lib/geminstaller/gem_command_line_proxy.rb +32 -0
  21. data/lib/geminstaller/gem_command_manager.rb +62 -0
  22. data/lib/geminstaller/gem_interaction_handler.rb +30 -0
  23. data/lib/geminstaller/gem_list_checker.rb +55 -0
  24. data/lib/geminstaller/gem_runner_proxy.rb +43 -0
  25. data/lib/geminstaller/gem_source_index_proxy.rb +21 -0
  26. data/lib/geminstaller/gem_spec_manager.rb +42 -0
  27. data/lib/geminstaller/geminstaller_error.rb +13 -0
  28. data/lib/geminstaller/hoe_extensions.rb +5 -0
  29. data/lib/geminstaller/install_processor.rb +56 -0
  30. data/lib/geminstaller/missing_dependency_finder.rb +41 -0
  31. data/lib/geminstaller/missing_file_error.rb +4 -0
  32. data/lib/geminstaller/noninteractive_chooser.rb +107 -0
  33. data/lib/geminstaller/output_filter.rb +49 -0
  34. data/lib/geminstaller/output_listener.rb +33 -0
  35. data/lib/geminstaller/output_observer.rb +32 -0
  36. data/lib/geminstaller/output_proxy.rb +36 -0
  37. data/lib/geminstaller/requires.rb +59 -0
  38. data/lib/geminstaller/rogue_gem_finder.rb +195 -0
  39. data/lib/geminstaller/ruby_gem.rb +44 -0
  40. data/lib/geminstaller/rubygems_exit.rb +5 -0
  41. data/lib/geminstaller/rubygems_extensions.rb +5 -0
  42. data/lib/geminstaller/unauthorized_dependency_prompt_error.rb +4 -0
  43. data/lib/geminstaller/unexpected_prompt_error.rb +4 -0
  44. data/lib/geminstaller/valid_platform_selector.rb +44 -0
  45. data/lib/geminstaller/version_specifier.rb +24 -0
  46. data/lib/geminstaller/yaml_loader.rb +22 -0
  47. data/lib/geminstaller.rb +102 -0
  48. data/start_local_gem_server.sh +1 -0
  49. data/test/test_all.rb +31 -0
  50. data/website/config.yaml +2 -0
  51. data/website/metainfo.yaml +72 -0
  52. data/website/src/code/index.page +25 -0
  53. data/website/src/community/index.page +14 -0
  54. data/website/src/community/links.page +9 -0
  55. data/website/src/default.css +168 -0
  56. data/website/src/default.template +41 -0
  57. data/website/src/documentation/documentation.page +417 -0
  58. data/website/src/documentation/index.page +88 -0
  59. data/website/src/documentation/tutorials.page +94 -0
  60. data/website/src/download.page +12 -0
  61. data/website/src/faq.page +7 -0
  62. data/website/src/index.page +38 -0
  63. metadata +107 -0
@@ -0,0 +1,43 @@
1
+ module GemInstaller
2
+ class Autogem
3
+ attr_writer :gem_command_manager, :gem_spec_manager, :gem_source_index_proxy
4
+ def autogem(gems)
5
+ @gem_source_index_proxy.refresh!
6
+ reversed_gems = gems.reverse!
7
+ @completed_names = []
8
+ @completed_gems = []
9
+ reversed_gems.each do |gem|
10
+ process_gem(gem)
11
+ end
12
+ @completed_gems
13
+ end
14
+
15
+ def process_gem(gem)
16
+ unless @completed_names.index(gem.name) or gem.no_autogem
17
+ invoke_require_gem_command(gem.name, gem.version)
18
+ @completed_names << gem.name
19
+ @completed_gems << gem
20
+ end
21
+ process_gem_dependencies(gem)
22
+ end
23
+
24
+ def process_gem_dependencies(gem)
25
+ # TODO: this method is duplicated in rogue_gem_finder. Should abstract and take a block
26
+ matching_gems = @gem_spec_manager.local_matching_gems(gem)
27
+ matching_gems.each do |matching_gem|
28
+ dependency_gems = @gem_command_manager.dependency(matching_gem.name, matching_gem.version.to_s)
29
+ dependency_gems.each do |dependency_gem|
30
+ process_gem(dependency_gem)
31
+ end
32
+ end
33
+ end
34
+
35
+ def invoke_require_gem_command(name, version)
36
+ if Gem::RubyGemsVersion.index('0.8') == 0
37
+ require_gem(name, version)
38
+ else
39
+ gem(name, version)
40
+ end
41
+ end
42
+ end
43
+ end
@@ -0,0 +1,69 @@
1
+ module GemInstaller
2
+ class Config
3
+ def initialize(yaml)
4
+ @yaml = yaml
5
+ @default_install_options_string = nil
6
+ end
7
+
8
+ def gems
9
+ parse_defaults
10
+ gem_defs = @yaml["gems"]
11
+ gems = []
12
+ gem_defs.each do |gem_def|
13
+ name = gem_def['name']
14
+ version = gem_def['version'].to_s
15
+ platform = gem_def['platform'].to_s
16
+ # get install_options for specific gem, if specified
17
+ install_options_string = gem_def['install_options'].to_s
18
+ # if no install_options were specified for specific gem, and default install_options were specified...
19
+ if install_options_string.empty? &&
20
+ !@default_install_options_string.nil? &&
21
+ !@default_install_options_string.empty? then
22
+ # then use the default install_options
23
+ install_options_string = @default_install_options_string
24
+ end
25
+ install_options_array = []
26
+ # if there was an install options string specified, default or gem-specific, parse it to an array
27
+ install_options_array = install_options_string.split(" ") unless install_options_string.empty?
28
+
29
+ check_for_upgrade = gem_def['check_for_upgrade']
30
+ if check_for_upgrade.nil? && defined? @default_check_for_upgrade then
31
+ check_for_upgrade = @default_check_for_upgrade
32
+ end
33
+
34
+ fix_dependencies = gem_def['fix_dependencies']
35
+ if fix_dependencies.nil? && defined? @default_fix_dependencies then
36
+ fix_dependencies = @default_fix_dependencies
37
+ end
38
+
39
+ no_autogem = gem_def['no_autogem']
40
+ if no_autogem.nil? && defined? @default_no_autogem then
41
+ no_autogem = @default_no_autogem
42
+ end
43
+
44
+ gem = GemInstaller::RubyGem.new(
45
+ name,
46
+ :version => version,
47
+ :platform => platform,
48
+ :install_options => install_options_array,
49
+ :check_for_upgrade => check_for_upgrade,
50
+ :no_autogem => no_autogem,
51
+ :fix_dependencies => fix_dependencies)
52
+ gems << gem
53
+ end
54
+ gems.sort!
55
+ return gems
56
+ end
57
+
58
+ protected
59
+
60
+ def parse_defaults
61
+ defaults = @yaml["defaults"]
62
+ return if defaults.nil?
63
+ @default_install_options_string = defaults['install_options']
64
+ @default_check_for_upgrade = defaults['check_for_upgrade']
65
+ @default_fix_dependencies = defaults['fix_dependencies']
66
+ @default_no_autogem = defaults['no_autogem']
67
+ end
68
+ end
69
+ end
@@ -0,0 +1,40 @@
1
+ dir = File.dirname(__FILE__)
2
+ require File.expand_path("#{dir}/requires.rb")
3
+
4
+ module GemInstaller
5
+ class ConfigBuilder
6
+ attr_reader :config_file_paths_array
7
+ attr_writer :file_reader
8
+ attr_writer :yaml_loader
9
+ attr_writer :config_file_paths
10
+
11
+ def self.default_config_file_path
12
+ 'geminstaller.yml'
13
+ end
14
+
15
+ def build_config
16
+ @config_file_paths ||= GemInstaller::ConfigBuilder.default_config_file_path
17
+ @config_file_paths_array = @config_file_paths.split(",")
18
+ merged_defaults = {}
19
+ merged_gems = {}
20
+ @config_file_paths_array.each do |path|
21
+ file_contents = @file_reader.read(path)
22
+ next unless file_contents
23
+ next if file_contents.empty?
24
+ file_contents_erb = ERB.new(%{#{file_contents}})
25
+ yaml = @yaml_loader.load(file_contents_erb.result)
26
+ merged_defaults.merge!(yaml['defaults']) unless yaml['defaults'].nil?
27
+ next unless yaml['gems']
28
+ yaml['gems'].each do |gem|
29
+ gem_key = [gem['name'],gem['version'],gem['platform']].join('-')
30
+ merged_gems[gem_key] = gem
31
+ end
32
+ end
33
+ merged_yaml = {}
34
+ merged_yaml['defaults'] = merged_defaults
35
+ merged_yaml['gems'] = merged_gems.values
36
+ config = GemInstaller::Config.new(merged_yaml)
37
+ config
38
+ end
39
+ end
40
+ end
@@ -0,0 +1,129 @@
1
+ module GemInstaller
2
+ class DependencyInjector
3
+ def registry
4
+ @registry ||= create_registry
5
+ end
6
+
7
+ def create_registry
8
+ # define the service registry
9
+ @registry = GemInstaller::Registry.new
10
+ end
11
+ end
12
+
13
+ class Registry
14
+ attr_accessor :file_reader, :yaml_loader, :output_proxy, :config_builder, :gem_source_index, :gem_runner_proxy
15
+ attr_accessor :gem_runner, :gem_command_manager, :gem_list_checker, :app, :arg_parser, :options, :noninteractive_chooser
16
+ attr_accessor :gem_interaction_handler, :install_processor, :missing_dependency_finder, :valid_platform_selector
17
+ attr_accessor :output_listener, :outs_output_observer, :errs_output_observer, :output_filter, :autogem, :rogue_gem_finder
18
+ attr_accessor :gem_spec_manager
19
+
20
+ def initialize
21
+ @options = {}
22
+ @arg_parser = GemInstaller::ArgParser.new
23
+ @arg_parser.options = @options
24
+
25
+ @file_reader = GemInstaller::FileReader.new
26
+ @yaml_loader = GemInstaller::YamlLoader.new
27
+ @gem_arg_processor = GemInstaller::GemArgProcessor.new
28
+ @version_specifier = GemInstaller::VersionSpecifier.new
29
+ @output_proxy = GemInstaller::OutputProxy.new
30
+ @output_proxy.options = @options
31
+ @output_filter = GemInstaller::OutputFilter.new
32
+ @output_filter.options = @options
33
+ @output_filter.output_proxy = @output_proxy
34
+
35
+
36
+ @output_listener = GemInstaller::OutputListener.new
37
+ @output_listener.output_filter = @output_filter
38
+
39
+ @valid_platform_selector = GemInstaller::ValidPlatformSelector.new
40
+ @valid_platform_selector.output_filter = @output_filter
41
+ @valid_platform_selector.options = @options
42
+
43
+ @config_builder = GemInstaller::ConfigBuilder.new
44
+ @config_builder.file_reader = @file_reader
45
+ @config_builder.yaml_loader = @yaml_loader
46
+
47
+ @gem_source_index = Gem::SourceIndex.new
48
+ @gem_source_index_proxy = GemInstaller::GemSourceIndexProxy.new
49
+ @gem_source_index_proxy.gem_source_index = @gem_source_index
50
+
51
+ @gem_interaction_handler = GemInstaller::GemInteractionHandler.new
52
+ @noninteractive_chooser_class = GemInstaller::NoninteractiveChooser
53
+ @gem_interaction_handler.noninteractive_chooser_class = @noninteractive_chooser_class
54
+ @gem_interaction_handler.valid_platform_selector = @valid_platform_selector
55
+
56
+ @outs_output_observer = GemInstaller::OutputObserver.new
57
+ @outs_output_observer.stream = :stdout
58
+ @outs_output_observer.register(@output_listener)
59
+ @errs_output_observer = GemInstaller::OutputObserver.new
60
+ @errs_output_observer.stream = :stderr
61
+ @errs_output_observer.register(@output_listener)
62
+
63
+ @enhanced_stream_ui = GemInstaller::EnhancedStreamUI.new
64
+ @enhanced_stream_ui.outs = @outs_output_observer
65
+ @enhanced_stream_ui.errs = @errs_output_observer
66
+ @enhanced_stream_ui.gem_interaction_handler = @gem_interaction_handler
67
+
68
+ @gem_runner_class = Gem::GemRunner
69
+ @gem_cmd_manager_class = Gem::CommandManager
70
+ @exact_match_list_command = GemInstaller::ExactMatchListCommand.new
71
+ @gem_runner_proxy = GemInstaller::GemRunnerProxy.new
72
+ @gem_runner_proxy.gem_runner_class = @gem_runner_class
73
+ @gem_runner_proxy.gem_cmd_manager_class = @gem_cmd_manager_class
74
+ @gem_runner_proxy.output_listener = @output_listener
75
+ @gem_runner_proxy.enhanced_stream_ui = @enhanced_stream_ui
76
+ @gem_runner_proxy.options = @options
77
+ @gem_runner_proxy.output_filter = @output_filter
78
+ @gem_runner_proxy.exact_match_list_command = @exact_match_list_command
79
+
80
+ @gem_spec_manager = GemInstaller::GemSpecManager.new
81
+ @gem_spec_manager.valid_platform_selector = @valid_platform_selector
82
+ @gem_spec_manager.gem_source_index_proxy = @gem_source_index_proxy
83
+ @gem_spec_manager.output_filter = @output_filter
84
+
85
+ @gem_command_manager = GemInstaller::GemCommandManager.new
86
+ @gem_command_manager.gem_spec_manager = @gem_spec_manager
87
+ @gem_command_manager.gem_runner_proxy = @gem_runner_proxy
88
+ @gem_command_manager.gem_interaction_handler = @gem_interaction_handler
89
+
90
+ @rogue_gem_finder = GemInstaller::RogueGemFinder.new
91
+ @rogue_gem_finder.gem_command_manager = @gem_command_manager
92
+ @rogue_gem_finder.gem_spec_manager = @gem_spec_manager
93
+ @rogue_gem_finder.output_proxy = @output_proxy
94
+
95
+ @autogem = GemInstaller::Autogem.new
96
+ @autogem.gem_command_manager = @gem_command_manager
97
+ @autogem.gem_source_index_proxy = @gem_source_index_proxy
98
+ @autogem.gem_spec_manager = @gem_spec_manager
99
+
100
+ @gem_list_checker = GemInstaller::GemListChecker.new
101
+ @gem_list_checker.gem_command_manager = @gem_command_manager
102
+ @gem_list_checker.gem_arg_processor = @gem_arg_processor
103
+ @gem_list_checker.version_specifier = @version_specifier
104
+
105
+ @missing_dependency_finder = GemInstaller::MissingDependencyFinder.new
106
+ @missing_dependency_finder.gem_command_manager = @gem_command_manager
107
+ @missing_dependency_finder.gem_spec_manager = @gem_spec_manager
108
+ @missing_dependency_finder.gem_arg_processor = @gem_arg_processor
109
+ @missing_dependency_finder.output_filter = @output_filter
110
+
111
+ @install_processor = GemInstaller::InstallProcessor.new
112
+ @install_processor.options = @options
113
+ @install_processor.gem_list_checker = @gem_list_checker
114
+ @install_processor.gem_command_manager = @gem_command_manager
115
+ @install_processor.gem_spec_manager = @gem_spec_manager
116
+ @install_processor.missing_dependency_finder = @missing_dependency_finder
117
+ @install_processor.output_filter = @output_filter
118
+
119
+ @app = GemInstaller::Application.new
120
+ @app.autogem = @autogem
121
+ @app.rogue_gem_finder = @rogue_gem_finder
122
+ @app.options = @options
123
+ @app.arg_parser = @arg_parser
124
+ @app.config_builder = @config_builder
125
+ @app.install_processor = @install_processor
126
+ @app.output_filter = @output_filter
127
+ end
128
+ end
129
+ end
@@ -0,0 +1,57 @@
1
+ module GemInstaller
2
+ class EnhancedStreamUI < Gem::StreamUI
3
+ attr_writer :gem_interaction_handler, :outs, :errs
4
+
5
+ def initialize()
6
+ # override default constructor to have no args
7
+ end
8
+
9
+ def ask_yes_no(question, default=nil)
10
+ begin
11
+ @gem_interaction_handler.handle_ask_yes_no(question)
12
+ rescue Exception => e
13
+ @outs.print(question)
14
+ @outs.flush
15
+ raise e
16
+ end
17
+ raise_unexpected_prompt_error(question)
18
+ end
19
+
20
+ def ask(question)
21
+ raise_unexpected_prompt_error(question)
22
+ end
23
+
24
+ def choose_from_list(question, list)
25
+ @gem_interaction_handler.handle_choose_from_list(question, list)
26
+ end
27
+
28
+ def terminate_interaction!(status=-1)
29
+ raise_error(status)
30
+ end
31
+
32
+ def terminate_interaction(status=0)
33
+ raise_error(status) unless status == 0
34
+ raise GemInstaller::RubyGemsExit.new(status)
35
+ end
36
+
37
+ def alert_error(statement, question=nil)
38
+ # if alert_error got called due to a GemInstaller::UnexpectedPromptError, re-throw it
39
+ last_exception = $!
40
+ if last_exception.class == GemInstaller::UnauthorizedDependencyPromptError || last_exception.class == GemInstaller::RubyGemsExit
41
+ raise last_exception
42
+ end
43
+ # otherwise let alert_error continue normally...
44
+ super(statement, question)
45
+ end
46
+
47
+ protected
48
+ def raise_error(status)
49
+ raise GemInstaller::GemInstallerError.new("RubyGems exited abnormally. Status: #{status}\n")
50
+ end
51
+
52
+ def raise_unexpected_prompt_error(question)
53
+ raise GemInstaller::UnexpectedPromptError.new("GemInstaller Internal Error - Unexpected prompt received from RubyGems: '#{question}'.")
54
+ end
55
+
56
+ end
57
+ end
@@ -0,0 +1,16 @@
1
+ module GemInstaller
2
+ class ExactMatchListCommand < Gem::ListCommand
3
+ def execute
4
+ string = get_one_optional_argument || ''
5
+ # This overrides the default RubyGems ListCommand behavior of doing a wildcard match. This caused problems
6
+ # when some gems (ActiveRecord-JDBC) caused exceptions during a remote list, causing a remote list
7
+ # of other gems (activerecord) to fail as well
8
+ options[:name] = /^#{string}$/i
9
+ # Do a little metaprogramming magic to avoid calling the problematic execute method on the ListCommand
10
+ # superclass, and instead directly call the method on the QueryCommand grandparent 'supersuperclass'
11
+ unbound_execute_method = Gem::QueryCommand.instance_method(:execute)
12
+ bound_execute_method = unbound_execute_method.bind(self)
13
+ bound_execute_method.call
14
+ end
15
+ end
16
+ end
@@ -0,0 +1,31 @@
1
+ module GemInstaller
2
+ class FileReader
3
+ def read(file_path)
4
+ file_contents = nil
5
+ if !File.exist?(file_path) then
6
+ raise GemInstaller::MissingFileError.new("#{file_path}")
7
+ end
8
+
9
+ file = nil
10
+ begin
11
+ file = do_open(file_path)
12
+ rescue
13
+ raise GemInstaller::GemInstallerError.new("Error: Unable open file #{file_path}. Please ensure that this file can be opened.\n")
14
+ end
15
+
16
+ begin
17
+ do_read(file)
18
+ rescue
19
+ raise GemInstaller::GemInstallerError.new("Error: Unable read file #{file_path}. Please ensure that this file can be read.\n")
20
+ end
21
+ end
22
+
23
+ def do_open(file_path)
24
+ File.open(file_path)
25
+ end
26
+
27
+ def do_read(file)
28
+ file.read
29
+ end
30
+ end
31
+ end
@@ -0,0 +1,44 @@
1
+ module GemInstaller
2
+ class GemArgProcessor
3
+ #Common Options:
4
+ # --source URL Use URL as the remote source for gems
5
+ # -p, --[no-]http-proxy [URL] Use HTTP proxy for remote operations
6
+ # -h, --help Get help on this command
7
+ # -v, --verbose Set the verbose level of output
8
+ # --config-file FILE Use this config file instead of default
9
+ # --backtrace Show stack backtrace on errors
10
+ # --debug Turn on Ruby debugging
11
+ GEM_COMMON_OPTIONS_WITHOUT_ARG = ['--no-http-proxy','-v','--verbose','--backtrace','--debug']
12
+ GEM_COMMON_OPTIONS_WITH_ARG = ['--source','-p','--http_proxy','--config-file']
13
+
14
+ # take an array of args, and strip all args that are not common gem command args
15
+ def strip_non_common_gem_args(args)
16
+ # I can't figure out a way to elegantly do this, so I hardcoded the options. Here's how you print them
17
+ # Gem::Command.common_options.each do |option|
18
+ # p option[0]
19
+ # end
20
+
21
+ common_args = []
22
+ i = 0
23
+ loop do
24
+ break if i == args.size
25
+ arg = args[i]
26
+ if GEM_COMMON_OPTIONS_WITHOUT_ARG.include?(arg)
27
+ common_args << arg
28
+ else
29
+ GEM_COMMON_OPTIONS_WITH_ARG.each do |option|
30
+ if arg.include?(option)
31
+ common_args << arg
32
+ unless arg.include?('=')
33
+ i += 1
34
+ common_args << args[i]
35
+ end
36
+ end
37
+ end
38
+ end
39
+ i += 1
40
+ end
41
+ common_args
42
+ end
43
+ end
44
+ end
@@ -0,0 +1,32 @@
1
+ module GemInstaller
2
+ class GemCommandLineProxy
3
+ GEM_ERROR_REGEXP = /^ERROR.*/
4
+ def run(args)
5
+ args_string = args.join(" ")
6
+ output = `gem #{args_string} 2>&1`
7
+ return_value = $?
8
+ lines = output.split("\n")
9
+ # return value is always zero on windows (from gem.bat), so we have to resort to parsing the output
10
+ error_in_output = false
11
+ lines.each do |line|
12
+ if line.match(GemInstaller::GemCommandLineProxy::GEM_ERROR_REGEXP)
13
+ error_in_output = true
14
+ break
15
+ end
16
+ end
17
+ if (return_value != 0 or error_in_output)
18
+ error_message = "Error: gem command failed. Command was 'gem #{args_string}', return value was '#{return_value}'. Output was:\n"
19
+ lines.each do |line|
20
+ error_message += ' ' + line + '\n'
21
+ end
22
+ raise GemInstaller::GemInstallerError.new(error_message)
23
+ end
24
+ return lines
25
+ end
26
+ end
27
+ end
28
+
29
+
30
+
31
+
32
+
@@ -0,0 +1,62 @@
1
+ module GemInstaller
2
+ class GemCommandManager
3
+ attr_writer :gem_spec_manager, :gem_runner_proxy, :gem_interaction_handler
4
+
5
+ def list_remote_gem(gem, additional_options)
6
+ run_args = ["list",gem.name,"--remote"]
7
+ run_args += additional_options
8
+ @gem_runner_proxy.run(run_args)
9
+ end
10
+
11
+ def uninstall_gem(gem)
12
+ return if !@gem_spec_manager.is_gem_installed?(gem)
13
+ @gem_interaction_handler.dependent_gem = gem
14
+ run_gem_command('uninstall',gem)
15
+ end
16
+
17
+ def install_gem(gem)
18
+ return if @gem_spec_manager.is_gem_installed?(gem)
19
+ @gem_interaction_handler.dependent_gem = gem
20
+ run_gem_command('install',gem)
21
+ end
22
+
23
+ def dependency(name, version, additional_options = [])
24
+ # it would be great to use the dependency --pipe option, but unfortunately, rubygems has a bug
25
+ # up to at least 0.9.2 where the pipe options uses 'puts', instead of 'say', so we can't capture it
26
+ # with enhanced_stream_ui. Patch submitted:
27
+ # http://rubyforge.org/tracker/index.php?func=detail&aid=9020&group_id=126&atid=577
28
+ run_args = ["dependency",/^#{name}$/,"--version",version]
29
+ run_args += additional_options
30
+ output_lines = @gem_runner_proxy.run(run_args)
31
+ # dependency output has all lines in the first element
32
+ output_array = output_lines[0].split("\n")
33
+ # drop the first line which just echoes the dependent gem
34
+ output_array.shift
35
+ # drop the line containing 'requires' (rubygems < 0.9.0)
36
+ if output_array[0] == ' Requires'
37
+ output_array.shift
38
+ end
39
+ # drop all empty lines
40
+ output_array.reject! { |line| line == "" }
41
+ # strip leading space
42
+ output_array.each { |line| line.strip! }
43
+ # convert into gems
44
+ output_gems = output_array.collect do |line|
45
+ name = line.split(' ')[0]
46
+ version_spec = line.split(/[()]/)[1]
47
+ GemInstaller::RubyGem.new(name, :version => version_spec)
48
+ end
49
+ end
50
+
51
+ def run_gem_command(gem_command,gem)
52
+ run_args = [gem_command,gem.name,"--version", "#{gem.version}"]
53
+ run_args += gem.install_options
54
+ @gem_runner_proxy.run(run_args)
55
+ end
56
+ end
57
+ end
58
+
59
+
60
+
61
+
62
+
@@ -0,0 +1,30 @@
1
+ module GemInstaller
2
+ class GemInteractionHandler
3
+ attr_writer :dependent_gem, :noninteractive_chooser_class, :valid_platform_selector
4
+ DEPENDENCY_PROMPT = 'Install required dependency'
5
+
6
+ def handle_ask_yes_no(question)
7
+ return unless question.index(DEPENDENCY_PROMPT)
8
+ message = "Error: RubyGems is prompting to install a required dependency, and you have not " +
9
+ "specified the '--install-dependencies' option for the current gem. You must modify your " +
10
+ "geminstaller config file to either specify the '--install-depencencies' (-y) " +
11
+ "option, or explicitly add an entry for the dependency gem earlier in the file.\n"
12
+ raise GemInstaller::UnauthorizedDependencyPromptError.new(message)
13
+ end
14
+
15
+ def handle_choose_from_list(question, list, noninteractive_chooser = nil)
16
+ noninteractive_chooser ||= @noninteractive_chooser_class.new
17
+ valid_platforms = nil
18
+ if dependent_gem_with_platform_specified?(list, noninteractive_chooser) or noninteractive_chooser.uninstall_list_type?(question)
19
+ valid_platforms = [@dependent_gem.platform]
20
+ else
21
+ valid_platforms = @valid_platform_selector.select(@dependent_gem.platform)
22
+ end
23
+ noninteractive_chooser.choose(question, list, @dependent_gem.name, @dependent_gem.version, valid_platforms)
24
+ end
25
+
26
+ def dependent_gem_with_platform_specified?(list, noninteractive_chooser)
27
+ noninteractive_chooser.dependent_gem?(@dependent_gem.name, list) and @dependent_gem.platform
28
+ end
29
+ end
30
+ end
@@ -0,0 +1,55 @@
1
+ module GemInstaller
2
+ class GemListChecker
3
+ attr_writer :gem_command_manager, :gem_arg_processor, :version_specifier
4
+
5
+ def find_remote_matching_gem(gem)
6
+ gem_list_match_regexp = /^#{gem.regexp_escaped_name} \(.*/
7
+ common_args = @gem_arg_processor.strip_non_common_gem_args(gem.install_options)
8
+ remote_list = @gem_command_manager.list_remote_gem(gem, common_args)
9
+
10
+ matched_lines = []
11
+ remote_list.each do |line|
12
+ if line.match(gem_list_match_regexp)
13
+ matched_lines << line
14
+ end
15
+ end
16
+
17
+ if matched_lines.size > 1
18
+ error_message = "Error: more than one remote gem matches (this should not happen and is probably a bug in geminstaller). Gem name = '#{gem.name}', install options = '#{gem.install_options}'. Matching remote gems: \n"
19
+ matched_lines.each do |line|
20
+ error_message += line + "\n"
21
+ end
22
+ raise GemInstaller::GemInstallerError.new(error_message)
23
+ end
24
+
25
+ if matched_lines.size == 0
26
+ error_message = "Error: Could not find remote gem to install. Gem name = '#{gem.name}', install options = '#{gem.install_options}'"
27
+ raise GemInstaller::GemInstallerError.new(error_message)
28
+ end
29
+
30
+ return matched_lines[0]
31
+ end
32
+
33
+ def verify_and_specify_remote_gem!(gem)
34
+ # TODO: this seems like it is a hack, but we must have a non-ambiguous version on the gem in order for
35
+ # noninteractive_chooser to be able to parse the gem list for multi-platform gems. This will not be necessary
36
+ # if a future RubyGems release allows specification/searching of the platform, because then we won't need noninteractive_chooser
37
+
38
+ version_list = available_versions(gem)
39
+ specified_version = @version_specifier.specify(gem.version, version_list, gem.name)
40
+ gem.version = specified_version
41
+ end
42
+
43
+ def available_versions(gem)
44
+ remote_match_line = find_remote_matching_gem(gem)
45
+ version_list = parse_out_version_list(remote_match_line)
46
+ end
47
+
48
+ def parse_out_version_list(line)
49
+ # return everything between first set of parenthesis
50
+ version_list = line.split(/[()]/)[1]
51
+ version_list
52
+ end
53
+
54
+ end
55
+ end
@@ -0,0 +1,43 @@
1
+ module GemInstaller
2
+ class GemRunnerProxy
3
+ attr_writer :gem_runner_class, :gem_cmd_manager_class, :output_listener, :exact_match_list_command
4
+ attr_writer :options, :enhanced_stream_ui, :output_filter
5
+
6
+ def run(args = [], stdin = [])
7
+ @output_filter.geminstaller_output(:commandecho,"'gem #{args.join(' ')}'\n")
8
+ gem_runner = create_gem_runner
9
+ # We have to manually initialize the configuration here, or else the GemCommandManager singleton
10
+ # will initialize with the (incorrect) default args when we call GemRunner.run.
11
+ gem_runner.do_configuration(args)
12
+ gem_cmd_manager = @gem_cmd_manager_class.instance
13
+ gem_cmd_manager.ui = @enhanced_stream_ui
14
+ gem_cmd_manager.register_command @exact_match_list_command
15
+
16
+ exit_status = nil
17
+ begin
18
+ gem_runner.run(args)
19
+ rescue GemInstaller::RubyGemsExit => normal_exit
20
+ exit_status = normal_exit.message
21
+ rescue GemInstaller::GemInstallerError => exit_error
22
+ raise_error_with_output(exit_error, args, @output_listener)
23
+ end
24
+ output_lines = @output_listener.read!
25
+ output_lines.push(exit_status) if exit_status
26
+ return output_lines
27
+ end
28
+
29
+ def create_gem_runner
30
+ rubygems_version = Gem::RubyGemsVersion
31
+ if rubygems_version.index('0.8') == 0
32
+ @gem_runner_class.new()
33
+ else
34
+ @gem_runner_class.new(:command_manager => @gem_cmd_manager_class)
35
+ end
36
+ end
37
+
38
+ def raise_error_with_output(exit_error, args, listener)
39
+ descriptive_exit_message = exit_error.descriptive_exit_message(exit_error.message, 'gem', args, listener)
40
+ raise exit_error.class.new(descriptive_exit_message)
41
+ end
42
+ end
43
+ end
@@ -0,0 +1,21 @@
1
+ module GemInstaller
2
+ class GemSourceIndexProxy
3
+ attr_writer :gem_source_index
4
+
5
+ def refresh!
6
+ @gem_source_index.refresh!
7
+ end
8
+
9
+ # NOTE: We will require an exact version requirement, rather than the standard default Gem version_requirement of ">= 0"
10
+ # GemInstaller has it's own default defined elsewhere
11
+ def search(gem_pattern, version_requirement)
12
+ # Returns an array of Gem::Specification objects
13
+ @gem_source_index.search(gem_pattern, version_requirement)
14
+ end
15
+ end
16
+ end
17
+
18
+
19
+
20
+
21
+