geminstaller 0.2.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- data/COPYING +1 -0
- data/History.txt +4 -0
- data/LICENSE +21 -0
- data/Manifest.txt +62 -0
- data/README.txt +60 -0
- data/Rakefile +92 -0
- data/TODO.txt +88 -0
- data/bin/geminstaller +30 -0
- data/geminstaller.yml +34 -0
- data/lib/geminstaller/application.rb +105 -0
- data/lib/geminstaller/arg_parser.rb +162 -0
- data/lib/geminstaller/autogem.rb +43 -0
- data/lib/geminstaller/config.rb +69 -0
- data/lib/geminstaller/config_builder.rb +40 -0
- data/lib/geminstaller/dependency_injector.rb +129 -0
- data/lib/geminstaller/enhanced_stream_ui.rb +57 -0
- data/lib/geminstaller/exact_match_list_command.rb +16 -0
- data/lib/geminstaller/file_reader.rb +31 -0
- data/lib/geminstaller/gem_arg_processor.rb +44 -0
- data/lib/geminstaller/gem_command_line_proxy.rb +32 -0
- data/lib/geminstaller/gem_command_manager.rb +62 -0
- data/lib/geminstaller/gem_interaction_handler.rb +30 -0
- data/lib/geminstaller/gem_list_checker.rb +55 -0
- data/lib/geminstaller/gem_runner_proxy.rb +43 -0
- data/lib/geminstaller/gem_source_index_proxy.rb +21 -0
- data/lib/geminstaller/gem_spec_manager.rb +42 -0
- data/lib/geminstaller/geminstaller_error.rb +13 -0
- data/lib/geminstaller/hoe_extensions.rb +5 -0
- data/lib/geminstaller/install_processor.rb +56 -0
- data/lib/geminstaller/missing_dependency_finder.rb +41 -0
- data/lib/geminstaller/missing_file_error.rb +4 -0
- data/lib/geminstaller/noninteractive_chooser.rb +107 -0
- data/lib/geminstaller/output_filter.rb +49 -0
- data/lib/geminstaller/output_listener.rb +33 -0
- data/lib/geminstaller/output_observer.rb +32 -0
- data/lib/geminstaller/output_proxy.rb +36 -0
- data/lib/geminstaller/requires.rb +59 -0
- data/lib/geminstaller/rogue_gem_finder.rb +195 -0
- data/lib/geminstaller/ruby_gem.rb +44 -0
- data/lib/geminstaller/rubygems_exit.rb +5 -0
- data/lib/geminstaller/rubygems_extensions.rb +5 -0
- data/lib/geminstaller/unauthorized_dependency_prompt_error.rb +4 -0
- data/lib/geminstaller/unexpected_prompt_error.rb +4 -0
- data/lib/geminstaller/valid_platform_selector.rb +44 -0
- data/lib/geminstaller/version_specifier.rb +24 -0
- data/lib/geminstaller/yaml_loader.rb +22 -0
- data/lib/geminstaller.rb +102 -0
- data/start_local_gem_server.sh +1 -0
- data/test/test_all.rb +31 -0
- data/website/config.yaml +2 -0
- data/website/metainfo.yaml +72 -0
- data/website/src/code/index.page +25 -0
- data/website/src/community/index.page +14 -0
- data/website/src/community/links.page +9 -0
- data/website/src/default.css +168 -0
- data/website/src/default.template +41 -0
- data/website/src/documentation/documentation.page +417 -0
- data/website/src/documentation/index.page +88 -0
- data/website/src/documentation/tutorials.page +94 -0
- data/website/src/download.page +12 -0
- data/website/src/faq.page +7 -0
- data/website/src/index.page +38 -0
- metadata +107 -0
@@ -0,0 +1,42 @@
|
|
1
|
+
module GemInstaller
|
2
|
+
class GemSpecManager
|
3
|
+
attr_writer :gem_source_index_proxy, :valid_platform_selector, :output_filter
|
4
|
+
|
5
|
+
def search(gem_pattern, version_requirement)
|
6
|
+
@gem_source_index_proxy.refresh!
|
7
|
+
@gem_source_index_proxy.search(gem_pattern, version_requirement)
|
8
|
+
end
|
9
|
+
|
10
|
+
def is_gem_installed?(gem)
|
11
|
+
return local_matching_gems(gem).size > 0
|
12
|
+
end
|
13
|
+
|
14
|
+
def all_local_gems
|
15
|
+
all_local_specs = search('',GemInstaller::RubyGem.default_version)
|
16
|
+
return [] unless all_local_specs
|
17
|
+
all_local_gems = all_local_specs.collect do |spec|
|
18
|
+
gem = GemInstaller::RubyGem.new(spec.name, :version => spec.version.version)
|
19
|
+
end
|
20
|
+
return all_local_gems
|
21
|
+
end
|
22
|
+
|
23
|
+
def local_matching_gems(gem, exact_platform_match = true)
|
24
|
+
gem_name_regexp = /^#{gem.regexp_escaped_name}$/
|
25
|
+
found_gem_specs = search(gem_name_regexp,gem.version)
|
26
|
+
return [] unless found_gem_specs
|
27
|
+
matching_gem_specs = found_gem_specs.select do |gem_spec|
|
28
|
+
valid_platforms = @valid_platform_selector.select(gem.platform, exact_platform_match)
|
29
|
+
valid_platforms.include?(gem_spec.platform)
|
30
|
+
end
|
31
|
+
matching_gems = matching_gem_specs.map do |gem_spec|
|
32
|
+
GemInstaller::RubyGem.new(gem_spec.name, {:version => gem_spec.version.version, :platform => gem_spec.platform })
|
33
|
+
end
|
34
|
+
return matching_gems
|
35
|
+
end
|
36
|
+
end
|
37
|
+
end
|
38
|
+
|
39
|
+
|
40
|
+
|
41
|
+
|
42
|
+
|
@@ -0,0 +1,13 @@
|
|
1
|
+
module GemInstaller
|
2
|
+
class GemInstallerError < RuntimeError
|
3
|
+
def descriptive_exit_message(message, command, args, listener)
|
4
|
+
args_string = args.join(" ")
|
5
|
+
descriptive_exit_message = "\n=========================================================\n"
|
6
|
+
descriptive_exit_message += "#{message}\n"
|
7
|
+
descriptive_exit_message += "Gem command was:\n #{command} #{args_string}\n\n"
|
8
|
+
descriptive_exit_message += "Gem command output was:\n"
|
9
|
+
descriptive_exit_message += listener.read!.join("\n")
|
10
|
+
descriptive_exit_message += "\n=========================================================\n\n"
|
11
|
+
end
|
12
|
+
end
|
13
|
+
end
|
@@ -0,0 +1,56 @@
|
|
1
|
+
module GemInstaller
|
2
|
+
class InstallProcessor
|
3
|
+
attr_writer :gem_list_checker, :gem_command_manager, :gem_spec_manager, :missing_dependency_finder, :options, :output_filter
|
4
|
+
def process(gems)
|
5
|
+
gems.each do |gem|
|
6
|
+
install_gem(gem)
|
7
|
+
end
|
8
|
+
end
|
9
|
+
|
10
|
+
def install_gem(gem)
|
11
|
+
already_specified = false
|
12
|
+
if gem.check_for_upgrade
|
13
|
+
@gem_list_checker.verify_and_specify_remote_gem!(gem)
|
14
|
+
already_specified = true
|
15
|
+
end
|
16
|
+
gem_is_installed = @gem_spec_manager.is_gem_installed?(gem)
|
17
|
+
if gem_is_installed
|
18
|
+
@output_filter.geminstaller_output(:debug,"Gem #{gem.name}, version #{gem.version} is already installed.\n")
|
19
|
+
else
|
20
|
+
@gem_list_checker.verify_and_specify_remote_gem!(gem) unless already_specified
|
21
|
+
@output_filter.geminstaller_output(:install,"Invoking gem install for #{gem.name}, version #{gem.version}.\n")
|
22
|
+
output_lines = @gem_command_manager.install_gem(gem)
|
23
|
+
print_dependency_install_messages(gem, output_lines) unless @options[:silent]
|
24
|
+
end
|
25
|
+
if gem.fix_dependencies
|
26
|
+
fix_dependencies(gem)
|
27
|
+
end
|
28
|
+
end
|
29
|
+
|
30
|
+
def print_dependency_install_messages(gem, output_lines)
|
31
|
+
output_lines.each do |line|
|
32
|
+
line =~ /Successfully installed /
|
33
|
+
match = $'
|
34
|
+
next unless match
|
35
|
+
next if match =~ /#{gem.name}-/
|
36
|
+
@output_filter.geminstaller_output(:install,"Rubygems automatically installed dependency gem #{match}\n")
|
37
|
+
end
|
38
|
+
end
|
39
|
+
|
40
|
+
def fix_dependencies(gem)
|
41
|
+
missing_dependencies = @missing_dependency_finder.find(gem)
|
42
|
+
while (missing_dependencies.size > 0)
|
43
|
+
missing_dependencies.each do |missing_dependency|
|
44
|
+
@output_filter.geminstaller_output(:install,"Installing #{missing_dependency.name} (#{missing_dependency.version})\n")
|
45
|
+
# recursively call install_gem to install the missing dependency. Since fix_dependencies
|
46
|
+
# should never be set on an auto-created missing dependency gem, there is no risk of an
|
47
|
+
# endless loop or stack overflow.
|
48
|
+
install_gem(missing_dependency)
|
49
|
+
end
|
50
|
+
# continue to look for and install missing dependencies until none are found
|
51
|
+
missing_dependencies = @missing_dependency_finder.find(gem)
|
52
|
+
end
|
53
|
+
end
|
54
|
+
|
55
|
+
end
|
56
|
+
end
|
@@ -0,0 +1,41 @@
|
|
1
|
+
module GemInstaller
|
2
|
+
class MissingDependencyFinder
|
3
|
+
attr_writer :gem_command_manager, :gem_spec_manager, :gem_arg_processor, :output_filter
|
4
|
+
def find(dependent_gem)
|
5
|
+
# NOTE: this doesn't resolve platforms, there's currently no way to know what
|
6
|
+
# platform should be selected for a dependency gem. Best-effort handling
|
7
|
+
# of ambiguous platforms on dependency gems will be handled elsewhere
|
8
|
+
matching_dependent_gems = @gem_spec_manager.local_matching_gems(dependent_gem)
|
9
|
+
missing_dependencies = []
|
10
|
+
install_options = dependent_gem.install_options
|
11
|
+
add_include_dependency_option(install_options)
|
12
|
+
common_args = @gem_arg_processor.strip_non_common_gem_args(install_options)
|
13
|
+
matching_dependent_gems.each do |matching_dependent_gem|
|
14
|
+
message_already_printed = false
|
15
|
+
dependency_gems = @gem_command_manager.dependency(matching_dependent_gem.name, matching_dependent_gem.version.to_s, common_args)
|
16
|
+
dependency_gems.each do |dependency_gem|
|
17
|
+
dependency_gem.install_options = install_options
|
18
|
+
local_matching_dependency_gems = @gem_spec_manager.local_matching_gems(dependency_gem, false)
|
19
|
+
unless local_matching_dependency_gems.size > 0
|
20
|
+
unless message_already_printed
|
21
|
+
@output_filter.geminstaller_output(:info, "Missing dependencies found for #{matching_dependent_gem.name} (#{matching_dependent_gem.version}):\n")
|
22
|
+
message_already_printed = true
|
23
|
+
end
|
24
|
+
# TODO: print install options too?
|
25
|
+
@output_filter.geminstaller_output(:info, " #{dependency_gem.name} (#{dependency_gem.version})\n")
|
26
|
+
missing_dependencies << dependency_gem
|
27
|
+
end
|
28
|
+
# recurse to find any missing dependencies in the tree
|
29
|
+
sub_dependencies = find(dependency_gem)
|
30
|
+
missing_dependencies += sub_dependencies if sub_dependencies.size > 0
|
31
|
+
end
|
32
|
+
end
|
33
|
+
return missing_dependencies
|
34
|
+
end
|
35
|
+
|
36
|
+
def add_include_dependency_option(install_options)
|
37
|
+
return if install_options.index('-y') or install_options.index('--include-dependencies')
|
38
|
+
install_options << '--include-dependencies'
|
39
|
+
end
|
40
|
+
end
|
41
|
+
end
|
@@ -0,0 +1,107 @@
|
|
1
|
+
module GemInstaller
|
2
|
+
# Format for "install" prompt list: "#{spec.name} #{spec.version} (#{spec.platform})"
|
3
|
+
# Format for "uninstall" prompt list: "#{spec.name}-#{spec.version}" for ruby, "#{spec.name}-#{spec.version}-#{spec.platform}" (gem.full_name) for binary
|
4
|
+
class NoninteractiveChooser
|
5
|
+
def initialize
|
6
|
+
@question = nil
|
7
|
+
end
|
8
|
+
|
9
|
+
def choose(question, list, dependent_gem_name, dependent_gem_version, valid_platforms)
|
10
|
+
@question = question
|
11
|
+
@list = list
|
12
|
+
@dependent_gem_name = dependent_gem_name
|
13
|
+
@dependent_gem_version = dependent_gem_version
|
14
|
+
@valid_platforms = valid_platforms
|
15
|
+
raise GemInstaller::GemInstallerError.new("Internal GemInstaller Error, unexpected choice prompt question: '#{question}'") unless
|
16
|
+
install_list_type? or uninstall_list_type?
|
17
|
+
|
18
|
+
raise GemInstaller::GemInstallerError.new("valid_platforms must be passed as an array.") unless
|
19
|
+
valid_platforms.respond_to? :shift
|
20
|
+
|
21
|
+
raise GemInstaller::GemInstallerError.new("Internal GemInstaller Error, multiple platforms cannot be specified for an uninstall prompt") if
|
22
|
+
uninstall_list_type? and valid_platforms.size > 1
|
23
|
+
|
24
|
+
index = nil
|
25
|
+
valid_platforms.each do |platform|
|
26
|
+
index = find_matching_line(platform)
|
27
|
+
break if index
|
28
|
+
end
|
29
|
+
|
30
|
+
return @list[index], index if index
|
31
|
+
|
32
|
+
# if we didn't find a match, raise a descriptive error
|
33
|
+
action = install_list_type? ? 'install' : 'uninstall'
|
34
|
+
name = @dependent_gem_name ? "#{@dependent_gem_name}" : "'any name'"
|
35
|
+
version = @dependent_gem_version ? "#{@dependent_gem_version}" : "'any version'"
|
36
|
+
platform = @valid_platforms ? " (#{@valid_platforms.join(' or ')})" : ''
|
37
|
+
error_message = "Error: Unable to select gem from list: \"#{name} #{version}#{platform}\". Available gems are:\n"
|
38
|
+
list.each do |item|
|
39
|
+
# skip last 'cancel' list entry, it's not a real gem
|
40
|
+
next if item == list.last
|
41
|
+
error_message += " " + item + "\n"
|
42
|
+
end
|
43
|
+
raise GemInstaller::GemInstallerError.new(error_message)
|
44
|
+
end
|
45
|
+
|
46
|
+
def find_matching_line(platform)
|
47
|
+
required_list_item_regexp = required_name_and_version_regexp + required_platform_regexp(platform)
|
48
|
+
line_selector = /^#{required_list_item_regexp}$/
|
49
|
+
@list.each_with_index do |item, index|
|
50
|
+
if item =~ line_selector
|
51
|
+
return index
|
52
|
+
end
|
53
|
+
end
|
54
|
+
return nil
|
55
|
+
end
|
56
|
+
|
57
|
+
def required_name_and_version_regexp
|
58
|
+
required_name_regexp = ".*?"
|
59
|
+
required_version_regexp = ".*?"
|
60
|
+
if uninstall_list_type? or dependent_gem?
|
61
|
+
# match the exact name and version if it's an uninstall prompt or a dependent gem
|
62
|
+
required_name_regexp = Regexp.escape(@dependent_gem_name) if @dependent_gem_name
|
63
|
+
required_version_regexp = Regexp.escape(@dependent_gem_version) if @dependent_gem_version
|
64
|
+
end
|
65
|
+
"#{required_name_regexp}[\s-]{0,1}#{required_version_regexp}"
|
66
|
+
end
|
67
|
+
|
68
|
+
def required_platform_regexp(platform_to_match)
|
69
|
+
return "" unless platform_to_match
|
70
|
+
required_platform = ""
|
71
|
+
escaped_platform_to_match = Regexp.escape(platform_to_match)
|
72
|
+
platform_regex = nil
|
73
|
+
if dependent_gem?
|
74
|
+
# do an exact match on the platform if this is the dependent gem
|
75
|
+
platform_regex = "#{escaped_platform_to_match}"
|
76
|
+
else
|
77
|
+
# do a wildcard match on the platform if it's not the dependent gem
|
78
|
+
platform_regex = ".*?#{escaped_platform_to_match}.*?"
|
79
|
+
end
|
80
|
+
# install list types always have the platform for each gem in parenthesis, even if it is ruby
|
81
|
+
if (install_list_type?)
|
82
|
+
required_platform = " \\(#{platform_regex}\\)"
|
83
|
+
end
|
84
|
+
# uninstall list types have the gem full_name, which is the platform for each gem appended after a dash, but only if it is not ruby
|
85
|
+
if (uninstall_list_type? && platform_to_match.to_s != GemInstaller::RubyGem.default_platform)
|
86
|
+
required_platform = "-.*?#{platform_regex}.*?"
|
87
|
+
end
|
88
|
+
required_platform
|
89
|
+
end
|
90
|
+
|
91
|
+
def install_list_type?(question = @question)
|
92
|
+
question =~ /to install/
|
93
|
+
end
|
94
|
+
|
95
|
+
def uninstall_list_type?(question = @question)
|
96
|
+
question =~ /to uninstall/
|
97
|
+
end
|
98
|
+
|
99
|
+
def dependent_gem?(dependent_gem_name = @dependent_gem_name, list = @list)
|
100
|
+
# return true if it's an install prompt, and the list contains the gem for which the original install request
|
101
|
+
# was made (in other words, it's a dependent gem, not a dependency gem)
|
102
|
+
install_format_exact_name_match_regexp = /^#{dependent_gem_name}\s.*/
|
103
|
+
install_list_type? and list[0] =~ install_format_exact_name_match_regexp
|
104
|
+
end
|
105
|
+
|
106
|
+
end
|
107
|
+
end
|
@@ -0,0 +1,49 @@
|
|
1
|
+
module GemInstaller
|
2
|
+
class OutputFilter
|
3
|
+
attr_writer :output_proxy, :options
|
4
|
+
|
5
|
+
def rubygems_output(type, message)
|
6
|
+
return if @options[:silent]
|
7
|
+
return unless rubygems_output_type_matches?(type)
|
8
|
+
output(:rubygems, type, message)
|
9
|
+
end
|
10
|
+
|
11
|
+
def geminstaller_output(type, message)
|
12
|
+
return if @options[:silent]
|
13
|
+
return unless geminstaller_output_type_matches?(type)
|
14
|
+
output(:geminstaller, type, message)
|
15
|
+
end
|
16
|
+
|
17
|
+
def output(source, type, message)
|
18
|
+
message = format_rubygems_message(type,message) if source == :rubygems
|
19
|
+
if (source == :geminstaller and type == :error)
|
20
|
+
@output_proxy.syserr(message)
|
21
|
+
|
22
|
+
else
|
23
|
+
@output_proxy.sysout(message)
|
24
|
+
end
|
25
|
+
end
|
26
|
+
|
27
|
+
def format_rubygems_message(type, message)
|
28
|
+
prefix = case type
|
29
|
+
when :stdout : "[RubyGems:stdout] "
|
30
|
+
when :stderr : "[RubyGems:stderr] "
|
31
|
+
end
|
32
|
+
"#{prefix}#{message}"
|
33
|
+
end
|
34
|
+
|
35
|
+
def rubygems_output_type_matches?(type)
|
36
|
+
return false unless @options[:rubygems_output]
|
37
|
+
return true if @options[:rubygems_output].include?(:all)
|
38
|
+
return true if @options[:rubygems_output].include?(type)
|
39
|
+
return false
|
40
|
+
end
|
41
|
+
|
42
|
+
def geminstaller_output_type_matches?(type)
|
43
|
+
return false unless @options[:geminstaller_output]
|
44
|
+
return true if @options[:geminstaller_output].include?(:all)
|
45
|
+
return true if @options[:geminstaller_output].include?(type)
|
46
|
+
return false
|
47
|
+
end
|
48
|
+
end
|
49
|
+
end
|
@@ -0,0 +1,33 @@
|
|
1
|
+
dir = File.dirname(__FILE__)
|
2
|
+
require File.expand_path("#{dir}/requires.rb")
|
3
|
+
|
4
|
+
module GemInstaller
|
5
|
+
class OutputListener
|
6
|
+
attr_writer :output_filter
|
7
|
+
|
8
|
+
def initialize
|
9
|
+
@messages = []
|
10
|
+
@output_filter = nil
|
11
|
+
end
|
12
|
+
|
13
|
+
def notify(msg, stream = :stdout)
|
14
|
+
@messages.push(msg)
|
15
|
+
return unless @output_filter
|
16
|
+
if stream == :stdout or stream == :stderr
|
17
|
+
@output_filter.rubygems_output(stream, msg)
|
18
|
+
else
|
19
|
+
raise GemInstaller::GemInstallerError.new("Invalid stream specified: #{@stream}")
|
20
|
+
end
|
21
|
+
end
|
22
|
+
|
23
|
+
def read
|
24
|
+
@messages.dup
|
25
|
+
end
|
26
|
+
|
27
|
+
def read!
|
28
|
+
messages = @messages.dup
|
29
|
+
@messages.clear
|
30
|
+
messages
|
31
|
+
end
|
32
|
+
end
|
33
|
+
end
|
@@ -0,0 +1,32 @@
|
|
1
|
+
module GemInstaller
|
2
|
+
class OutputObserver
|
3
|
+
attr_writer :stream
|
4
|
+
# TODO: GemRunnerProxy should raise exception if listener still has any leftover output when run is invoked.
|
5
|
+
def initialize
|
6
|
+
@stream = :stdout
|
7
|
+
@listeners = []
|
8
|
+
end
|
9
|
+
|
10
|
+
def register(listener)
|
11
|
+
listener = [listener] unless listener.is_a?(Array)
|
12
|
+
@listeners += listener
|
13
|
+
end
|
14
|
+
|
15
|
+
def unregister(listener)
|
16
|
+
@listeners.delete(listener)
|
17
|
+
end
|
18
|
+
|
19
|
+
def print(output)
|
20
|
+
@listeners.each do |listener|
|
21
|
+
listener.notify(output, @stream)
|
22
|
+
end
|
23
|
+
end
|
24
|
+
|
25
|
+
def puts(output)
|
26
|
+
print("#{output}\n")
|
27
|
+
end
|
28
|
+
|
29
|
+
def flush
|
30
|
+
end
|
31
|
+
end
|
32
|
+
end
|
@@ -0,0 +1,36 @@
|
|
1
|
+
module GemInstaller
|
2
|
+
class OutputProxy
|
3
|
+
attr_writer :options
|
4
|
+
def default_stream=(stream)
|
5
|
+
raise GemInstaller::GemInstallerError.new("Invalid default stream: #{stream}") unless stream == :stderr or stream == :stdout
|
6
|
+
@default_stream = stream
|
7
|
+
end
|
8
|
+
|
9
|
+
def sysout(out)
|
10
|
+
return if silent?
|
11
|
+
$stdout.print out
|
12
|
+
end
|
13
|
+
|
14
|
+
def syserr(err)
|
15
|
+
return if silent?
|
16
|
+
if @options[:redirect_stderr_to_stdout]
|
17
|
+
$stdout.print err
|
18
|
+
else
|
19
|
+
$stderr.print err
|
20
|
+
end
|
21
|
+
end
|
22
|
+
|
23
|
+
# TODO: should remove this, make callers explicitly choose.
|
24
|
+
def output(output)
|
25
|
+
if @default_stream == :stdout
|
26
|
+
sysout(output)
|
27
|
+
else
|
28
|
+
syserr(output)
|
29
|
+
end
|
30
|
+
end
|
31
|
+
|
32
|
+
def silent?
|
33
|
+
@options && @options[:silent]
|
34
|
+
end
|
35
|
+
end
|
36
|
+
end
|
@@ -0,0 +1,59 @@
|
|
1
|
+
dir = File.dirname(__FILE__)
|
2
|
+
|
3
|
+
# requires for rubygems
|
4
|
+
require 'rubygems'
|
5
|
+
require 'rubygems/doc_manager'
|
6
|
+
require 'rubygems/config_file'
|
7
|
+
require 'rubygems/cmd_manager'
|
8
|
+
require 'rubygems/gem_runner'
|
9
|
+
require 'rubygems/remote_installer'
|
10
|
+
require 'rubygems/installer'
|
11
|
+
require 'rubygems/validator'
|
12
|
+
|
13
|
+
# third party libs
|
14
|
+
require 'erb'
|
15
|
+
require 'optparse'
|
16
|
+
require 'yaml'
|
17
|
+
require 'fileutils'
|
18
|
+
require 'tempfile'
|
19
|
+
|
20
|
+
# third party lib extensions
|
21
|
+
require File.expand_path("#{dir}/rubygems_extensions")
|
22
|
+
|
23
|
+
# internal files
|
24
|
+
require File.expand_path("#{dir}/../geminstaller")
|
25
|
+
require File.expand_path("#{dir}/application")
|
26
|
+
require File.expand_path("#{dir}/arg_parser")
|
27
|
+
require File.expand_path("#{dir}/autogem")
|
28
|
+
require File.expand_path("#{dir}/config")
|
29
|
+
require File.expand_path("#{dir}/config_builder")
|
30
|
+
require File.expand_path("#{dir}/dependency_injector")
|
31
|
+
require File.expand_path("#{dir}/enhanced_stream_ui")
|
32
|
+
require File.expand_path("#{dir}/exact_match_list_command")
|
33
|
+
require File.expand_path("#{dir}/file_reader")
|
34
|
+
require File.expand_path("#{dir}/gem_arg_processor")
|
35
|
+
require File.expand_path("#{dir}/gem_command_line_proxy")
|
36
|
+
require File.expand_path("#{dir}/gem_command_manager")
|
37
|
+
require File.expand_path("#{dir}/gem_interaction_handler")
|
38
|
+
require File.expand_path("#{dir}/gem_list_checker")
|
39
|
+
require File.expand_path("#{dir}/gem_runner_proxy")
|
40
|
+
require File.expand_path("#{dir}/gem_source_index_proxy")
|
41
|
+
require File.expand_path("#{dir}/gem_spec_manager")
|
42
|
+
require File.expand_path("#{dir}/geminstaller_error")
|
43
|
+
require File.expand_path("#{dir}/install_processor")
|
44
|
+
require File.expand_path("#{dir}/missing_dependency_finder")
|
45
|
+
require File.expand_path("#{dir}/missing_file_error")
|
46
|
+
require File.expand_path("#{dir}/noninteractive_chooser")
|
47
|
+
require File.expand_path("#{dir}/output_filter")
|
48
|
+
require File.expand_path("#{dir}/output_listener")
|
49
|
+
require File.expand_path("#{dir}/output_observer")
|
50
|
+
require File.expand_path("#{dir}/output_proxy")
|
51
|
+
require File.expand_path("#{dir}/rogue_gem_finder")
|
52
|
+
require File.expand_path("#{dir}/rubygems_exit")
|
53
|
+
require File.expand_path("#{dir}/ruby_gem")
|
54
|
+
require File.expand_path("#{dir}/unexpected_prompt_error")
|
55
|
+
require File.expand_path("#{dir}/unauthorized_dependency_prompt_error")
|
56
|
+
require File.expand_path("#{dir}/valid_platform_selector")
|
57
|
+
require File.expand_path("#{dir}/version_specifier")
|
58
|
+
require File.expand_path("#{dir}/yaml_loader")
|
59
|
+
|
@@ -0,0 +1,195 @@
|
|
1
|
+
module GemInstaller
|
2
|
+
class RogueGemFinder
|
3
|
+
attr_writer :output_proxy, :gem_command_manager, :gem_spec_manager, :boilerplate_lines, :preinstalled_gem_names, :preinstalled_comment
|
4
|
+
|
5
|
+
def print_rogue_gems(config_gems, config_file_paths)
|
6
|
+
@boilerplate_lines ||= default_boilerplate_lines(config_gems, config_file_paths)
|
7
|
+
@preinstalled_gem_names ||= default_preinstalled_gem_names
|
8
|
+
@preinstalled_comment ||= default_preinstalled_comment
|
9
|
+
@config_gems_with_dependencies = []
|
10
|
+
config_gems.each do |config_gem|
|
11
|
+
process_gem(config_gem)
|
12
|
+
end
|
13
|
+
all_local_gems = @gem_spec_manager.all_local_gems
|
14
|
+
rogue_gems = []
|
15
|
+
all_local_gems.each do |local_gem|
|
16
|
+
config_match_found_for_local = false
|
17
|
+
@config_gems_with_dependencies.each do |config_gem|
|
18
|
+
name_matches = config_gem.name == local_gem.name
|
19
|
+
config_gem_version_requirement = Gem::Version::Requirement.new [config_gem.version]
|
20
|
+
local_gem_version = Gem::Version.new(local_gem.version)
|
21
|
+
version_matches = config_gem_version_requirement.satisfied_by?(local_gem_version)
|
22
|
+
if (name_matches and version_matches)
|
23
|
+
config_match_found_for_local = true
|
24
|
+
break
|
25
|
+
end
|
26
|
+
end
|
27
|
+
rogue_gems << local_gem unless config_match_found_for_local
|
28
|
+
end
|
29
|
+
yaml = format_to_yaml(rogue_gems)
|
30
|
+
|
31
|
+
handle_output(yaml)
|
32
|
+
end
|
33
|
+
|
34
|
+
def default_boilerplate_lines(config_gems, config_file_paths)
|
35
|
+
boilerplate = []
|
36
|
+
boilerplate << [
|
37
|
+
"#",
|
38
|
+
"# This is a GemInstaller config file (http://geminstaller.rubyforge.org)",
|
39
|
+
"# It was generated using the 'geminstaller --print-rogue-gems' option on #{Time.now}",
|
40
|
+
"#",
|
41
|
+
"# You can bootstrap your config by piping the output to a file: ",
|
42
|
+
"# 'geminstaller --print-rogue-gems > geminstaller.yml'",
|
43
|
+
"#",
|
44
|
+
"# You can then install these gems on another system by running geminstaller with this file.",
|
45
|
+
"#"
|
46
|
+
]
|
47
|
+
|
48
|
+
if config_file_paths.size == 0
|
49
|
+
boilerplate << "# Since there was no config file specified, the 'gems:' section below lists all gems on your system."
|
50
|
+
else
|
51
|
+
boilerplate << "# The following config file(s) and gems were already specified:"
|
52
|
+
boilerplate << "# Files:"
|
53
|
+
config_file_paths.each do |config_file_path|
|
54
|
+
boilerplate << "# * " + config_file_path
|
55
|
+
end
|
56
|
+
boilerplate << "# Gems:"
|
57
|
+
if config_gems.size > 0
|
58
|
+
config_gems.each do |config_gem|
|
59
|
+
boilerplate << "# * #{config_gem.name} #{config_gem.version}"
|
60
|
+
end
|
61
|
+
else
|
62
|
+
boilerplate << "# No Gems"
|
63
|
+
end
|
64
|
+
end
|
65
|
+
boilerplate << "#"
|
66
|
+
boilerplate << "defaults:"
|
67
|
+
boilerplate << " install_options: --include-dependencies"
|
68
|
+
return boilerplate
|
69
|
+
end
|
70
|
+
|
71
|
+
def default_preinstalled_gem_names
|
72
|
+
# This is the list of preinstalled gems from the Ruby windows 1-click installer, v186-25
|
73
|
+
#
|
74
|
+
# fxri (0.3.6)
|
75
|
+
# Graphical interface to the RI documentation, with search engine.
|
76
|
+
#
|
77
|
+
# fxruby (1.6.6)
|
78
|
+
# FXRuby is the Ruby binding to the FOX GUI toolkit.
|
79
|
+
#
|
80
|
+
# hpricot (0.4)
|
81
|
+
# a swift, liberal HTML parser with a fantastic library
|
82
|
+
#
|
83
|
+
# log4r (1.0.5)
|
84
|
+
# Log4r is a comprehensive and flexible logging library for Ruby.
|
85
|
+
#
|
86
|
+
# rake (0.7.2)
|
87
|
+
# Ruby based make-like utility.
|
88
|
+
#
|
89
|
+
# sources (0.0.1)
|
90
|
+
# This package provides download sources for remote gem installation
|
91
|
+
#
|
92
|
+
# win32-clipboard (0.4.1)
|
93
|
+
# A package for interacting with the Windows clipboard
|
94
|
+
#
|
95
|
+
# win32-dir (0.3.1)
|
96
|
+
# Extra constants and methods for the Dir class on Windows.
|
97
|
+
#
|
98
|
+
# win32-eventlog (0.4.3)
|
99
|
+
# Interface for the MS Windows Event Log.
|
100
|
+
#
|
101
|
+
# win32-file (0.5.3)
|
102
|
+
# Extra or redefined methods for the File class on Windows.
|
103
|
+
#
|
104
|
+
# win32-file-stat (1.2.3)
|
105
|
+
# A File::Stat class tailored to MS Windows
|
106
|
+
#
|
107
|
+
# win32-process (0.5.1)
|
108
|
+
# Adds fork, wait, wait2, waitpid, waitpid2 and a special kill method
|
109
|
+
#
|
110
|
+
# win32-sapi (0.1.3)
|
111
|
+
# An interface to the MS SAPI (Sound API) library.
|
112
|
+
#
|
113
|
+
# win32-sound (0.4.0)
|
114
|
+
# A package for playing with sound on Windows.
|
115
|
+
#
|
116
|
+
# windows-pr (0.6.2)
|
117
|
+
# Windows functions and constants predefined via Win32API
|
118
|
+
|
119
|
+
if RUBY_PLATFORM =~ /mswin/
|
120
|
+
return [
|
121
|
+
'fxri',
|
122
|
+
'fxruby',
|
123
|
+
'hpricot',
|
124
|
+
'log4r',
|
125
|
+
'rake',
|
126
|
+
'sources',
|
127
|
+
'win32-clipboard',
|
128
|
+
'win32-dir',
|
129
|
+
'win32-eventlog',
|
130
|
+
'win32-file',
|
131
|
+
'win32-file-stat',
|
132
|
+
'win32-process',
|
133
|
+
'win32-sapi',
|
134
|
+
'win32-sound',
|
135
|
+
'windows-pr'
|
136
|
+
]
|
137
|
+
end
|
138
|
+
return ['sources']
|
139
|
+
end
|
140
|
+
|
141
|
+
def default_preinstalled_comment
|
142
|
+
"# NOTE: This gem may have been automatially installed with Ruby, and not actually be used by your app(s)."
|
143
|
+
end
|
144
|
+
|
145
|
+
def handle_output(yaml)
|
146
|
+
yaml_lines = yaml.split("\n")
|
147
|
+
yaml_doc_separator = yaml_lines.delete_at(0)
|
148
|
+
|
149
|
+
output = []
|
150
|
+
output.push(yaml_doc_separator)
|
151
|
+
|
152
|
+
output << @boilerplate_lines
|
153
|
+
|
154
|
+
yaml_lines.each do |yaml_line|
|
155
|
+
name_parser_regexp = /- name: (.*)/
|
156
|
+
yaml_line =~ name_parser_regexp
|
157
|
+
gem_name = $1
|
158
|
+
preinstalled_comment = ''
|
159
|
+
if @preinstalled_gem_names.include?(gem_name)
|
160
|
+
preinstalled_comment = " " + @preinstalled_comment
|
161
|
+
end
|
162
|
+
output.push yaml_line + preinstalled_comment
|
163
|
+
end
|
164
|
+
|
165
|
+
output_string = output.join("\n")
|
166
|
+
@output_proxy.sysout output_string
|
167
|
+
output_string
|
168
|
+
end
|
169
|
+
|
170
|
+
def process_gem(gem)
|
171
|
+
@config_gems_with_dependencies << gem
|
172
|
+
process_gem_dependencies(gem)
|
173
|
+
end
|
174
|
+
|
175
|
+
def process_gem_dependencies(gem)
|
176
|
+
# TODO: this method is duplicated in autogem Should abstract and take a block
|
177
|
+
matching_gems = @gem_spec_manager.local_matching_gems(gem)
|
178
|
+
matching_gems.each do |matching_gem|
|
179
|
+
dependency_gems = @gem_command_manager.dependency(matching_gem.name, matching_gem.version.to_s)
|
180
|
+
dependency_gems.each do |dependency_gem|
|
181
|
+
process_gem(dependency_gem)
|
182
|
+
end
|
183
|
+
end
|
184
|
+
end
|
185
|
+
|
186
|
+
def format_to_yaml(gems)
|
187
|
+
names_and_versions = []
|
188
|
+
gems.each do |gem|
|
189
|
+
names_and_versions << {'name' => gem.name, 'version' => gem.version}
|
190
|
+
end
|
191
|
+
hash_for_yaml = {'gems' => names_and_versions}
|
192
|
+
YAML.dump(hash_for_yaml)
|
193
|
+
end
|
194
|
+
end
|
195
|
+
end
|