1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207
|
# frozen_string_literal: true
require_relative '../command'
require_relative '../local_remote_options'
require_relative '../version_option'
class Gem::Commands::DependencyCommand < Gem::Command
include Gem::LocalRemoteOptions
include Gem::VersionOption
def initialize
super 'dependency',
'Show the dependencies of an installed gem',
:version => Gem::Requirement.default, :domain => :local
add_version_option
add_platform_option
add_prerelease_option
add_option('-R', '--[no-]reverse-dependencies',
'Include reverse dependencies in the output') do
|value, options|
options[:reverse_dependencies] = value
end
add_option('-p', '--pipe',
"Pipe Format (name --version ver)") do |value, options|
options[:pipe_format] = value
end
add_local_remote_options
end
def arguments # :nodoc:
"REGEXP show dependencies for gems whose names start with REGEXP"
end
def defaults_str # :nodoc:
"--local --version '#{Gem::Requirement.default}' --no-reverse-dependencies"
end
def description # :nodoc:
<<-EOF
The dependency commands lists which other gems a given gem depends on. For
local gems only the reverse dependencies can be shown (which gems depend on
the named gem).
The dependency list can be displayed in a format suitable for piping for
use with other commands.
EOF
end
def usage # :nodoc:
"#{program_name} REGEXP"
end
def fetch_remote_specs(name, requirement, prerelease) # :nodoc:
fetcher = Gem::SpecFetcher.fetcher
specs_type = prerelease ? :complete : :released
ss = if name.nil?
fetcher.detect(specs_type) { true }
else
fetcher.detect(specs_type) do |name_tuple|
name === name_tuple.name && requirement.satisfied_by?(name_tuple.version)
end
end
ss.map {|tuple, source| source.fetch_spec(tuple) }
end
def fetch_specs(name_pattern, requirement, prerelease) # :nodoc:
specs = []
if local?
specs.concat Gem::Specification.stubs.find_all {|spec|
name_matches = name_pattern ? name_pattern =~ spec.name : true
version_matches = requirement.satisfied_by?(spec.version)
name_matches and version_matches
}.map(&:to_spec)
end
specs.concat fetch_remote_specs name_pattern, requirement, prerelease if remote?
ensure_specs specs
specs.uniq.sort
end
def display_pipe(specs) # :nodoc:
specs.each do |spec|
unless spec.dependencies.empty?
spec.dependencies.sort_by {|dep| dep.name }.each do |dep|
say "#{dep.name} --version '#{dep.requirement}'"
end
end
end
end
def display_readable(specs, reverse) # :nodoc:
response = String.new
specs.each do |spec|
response << print_dependencies(spec)
unless reverse[spec.full_name].empty?
response << " Used by\n"
reverse[spec.full_name].each do |sp, dep|
response << " #{sp} (#{dep})\n"
end
end
response << "\n"
end
say response
end
def execute
ensure_local_only_reverse_dependencies
pattern = name_pattern options[:args]
requirement = Gem::Requirement.new options[:version]
specs = fetch_specs pattern, requirement, options[:prerelease]
reverse = reverse_dependencies specs
if options[:pipe_format]
display_pipe specs
else
display_readable specs, reverse
end
end
def ensure_local_only_reverse_dependencies # :nodoc:
if options[:reverse_dependencies] and remote? and not local?
alert_error 'Only reverse dependencies for local gems are supported.'
terminate_interaction 1
end
end
def ensure_specs(specs) # :nodoc:
return unless specs.empty?
patterns = options[:args].join ','
say "No gems found matching #{patterns} (#{options[:version]})" if
Gem.configuration.verbose
terminate_interaction 1
end
def print_dependencies(spec, level = 0) # :nodoc:
response = String.new
response << ' ' * level + "Gem #{spec.full_name}\n"
unless spec.dependencies.empty?
spec.dependencies.sort_by {|dep| dep.name }.each do |dep|
response << ' ' * level + " #{dep}\n"
end
end
response
end
def reverse_dependencies(specs) # :nodoc:
reverse = Hash.new {|h, k| h[k] = [] }
return reverse unless options[:reverse_dependencies]
specs.each do |spec|
reverse[spec.full_name] = find_reverse_dependencies spec
end
reverse
end
##
# Returns an Array of [specification, dep] that are satisfied by +spec+.
def find_reverse_dependencies(spec) # :nodoc:
result = []
Gem::Specification.each do |sp|
sp.dependencies.each do |dep|
dep = Gem::Dependency.new(*dep) unless Gem::Dependency === dep
if spec.name == dep.name and
dep.requirement.satisfied_by?(spec.version)
result << [sp.full_name, dep]
end
end
end
result
end
private
def name_pattern(args)
return if args.empty?
if args.length == 1 and args.first =~ /\A(.*)(i)?\z/m
flags = $2 ? Regexp::IGNORECASE : nil
Regexp.new $1, flags
else
/\A#{Regexp.union(*args)}/
end
end
end
|