class GemMirror::GemsFetcher
The GemsFetcher
class is responsible for downloading Gems from an external source as well as downloading all the associated dependencies.
@!attribute [r] source
@return [Source]
@!attribute [r] versions_file
@return [GemMirror::VersionsFile]
Attributes
Public Class Methods
@param [Source] source @param [GemMirror::VersionsFile] versions_file
# File lib/gem_mirror/gems_fetcher.rb 20 def initialize(source, versions_file) 21 @source = source 22 @versions_file = versions_file 23 end
Public Instance Methods
Processes a list of Gems and sets their versions to the latest one available in case no specific version is given.
@param [Array] gems @return [Array]
# File lib/gem_mirror/gems_fetcher.rb 211 def assign_gem_versions(gems) 212 gems.map do |gem| 213 unless gem.version? 214 latest = versions_file.versions_for(gem.name).last 215 gem = Gem.new(gem.name, latest.to_s) if latest 216 end 217 218 gem 219 end 220 end
# File lib/gem_mirror/gems_fetcher.rb 233 def configuration 234 GemMirror.configuration 235 end
Returns an Array containing all the dependencies of a given Gem
specification.
@param [Gem::Specification] spec @return [Array]
# File lib/gem_mirror/gems_fetcher.rb 174 def dependencies_for(spec) 175 possible_dependencies = if configuration.development 176 spec.dependencies 177 else 178 spec.runtime_dependencies 179 end 180 181 dependencies = filter_dependencies(possible_dependencies) 182 183 assign_gem_versions(dependencies) 184 end
Fetches the Gems and all associated dependencies.
# File lib/gem_mirror/gems_fetcher.rb 28 def fetch 29 source.gems.each do |gem| 30 versions_for(gem).each do |version| 31 filename = gem.filename(version) 32 begin 33 satisfied = gem.requirement.satisfied_by?(version) 34 rescue StandardError 35 logger.debug("Error determining is requirement satisfied for #{filename}") 36 end 37 name = gem.name 38 39 if gem_exists?(filename) || ignore_gem?(name, version) || !satisfied 40 logger.debug("Skipping #{filename}") 41 next 42 end 43 44 # Prevent circular dependencies from messing things up. 45 configuration.ignore_gem(gem.name, version) 46 47 spec = fetch_specification(gem, version) 48 49 next unless spec 50 51 spec = load_specification(spec) 52 deps = dependencies_for(spec) 53 54 unless deps.empty? 55 logger.info("Fetching dependencies for #{filename}") 56 57 fetch_dependencies(deps) 58 end 59 60 logger.info("Fetching #{filename}") 61 62 gemfile = fetch_gem(gem, version) 63 64 configuration.mirror_directory.add_file(filename, gemfile) if gemfile 65 end 66 end 67 end
Fetches the Gem
files for the specified dependencies.
@param [Array] deps
# File lib/gem_mirror/gems_fetcher.rb 163 def fetch_dependencies(deps) 164 self.class.new(source.updated(deps), versions_file).fetch 165 end
Tries to download the Gemfile for the specified Gem
and version.
@param [GemMirror::Gem] gem @param [Gem::Version] version @return [String]
# File lib/gem_mirror/gems_fetcher.rb 125 def fetch_gem(gem, version) 126 gemfile = nil 127 filename = gem.filename(version) 128 129 begin 130 gemfile = source.fetch_gem(gem.name, version) 131 rescue StandardError => e 132 logger.error("Failed to retrieve #{filename}: #{e.message}") 133 logger.debug("Adding #{filename} to the list of ignored Gems") 134 135 configuration.ignore_gem(gem.name, version) 136 end 137 138 gemfile 139 end
Tries to download the specification for a Gem
and version. This method returns the raw inflated data instead of an instance of `Gem::Specification`.
@param [GemMirror::Gem] gem @param [Gem::Version] version @return [String]
# File lib/gem_mirror/gems_fetcher.rb 102 def fetch_specification(gem, version) 103 specification = nil 104 filename = gem.filename(version) 105 106 begin 107 specification = source.fetch_specification(gem.name, version) 108 rescue StandardError => e 109 logger.error("Failed to retrieve #{filename}: #{e.message}") 110 logger.debug("Adding #{filename} to the list of ignored Gems") 111 112 configuration.ignore_gem(gem.name, version) 113 end 114 115 specification 116 end
Filters a list of dependencies based on whether or not they are ignored.
@param [Array] possible_dependencies @return [Array]
# File lib/gem_mirror/gems_fetcher.rb 192 def filter_dependencies(possible_dependencies) 193 dependencies = [] 194 195 possible_dependencies.each do |dependency| 196 gem = Gem.new(dependency.name, dependency.requirement) 197 198 dependencies << gem unless ignore_gem?(gem.name, gem.version) 199 end 200 201 dependencies 202 end
Checks if a given Gem
has already been downloaded.
@param [String] filename @return [TrueClass|FalseClass]
# File lib/gem_mirror/gems_fetcher.rb 243 def gem_exists?(filename) 244 configuration.mirror_directory.file_exists?(filename) 245 end
@see GemMirror::Configuration#ignore_gem?
# File lib/gem_mirror/gems_fetcher.rb 250 def ignore_gem?(*args) 251 configuration.ignore_gem?(*args) 252 end
Reads the inflated data of a Gemspec and returns the loaded specification instance.
@param [String] raw_spec @return [Gem::Specification]
# File lib/gem_mirror/gems_fetcher.rb 148 def load_specification(raw_spec) 149 stream = Zlib::Inflate.new 150 content = stream.inflate(raw_spec) 151 152 stream.finish 153 stream.close 154 155 Marshal.load(content) 156 end
@see GemMirror::Configuration#logger
@return [Logger]
# File lib/gem_mirror/gems_fetcher.rb 226 def logger 227 configuration.logger 228 end
Returns an Array containing the versions that should be fetched for a Gem
.
@param [GemMirror::Gem] gem @return [Array]
# File lib/gem_mirror/gems_fetcher.rb 76 def versions_for(gem) 77 available = versions_file.versions_for(gem.name) 78 versions = gem.version? ? [gem.version] : available 79 available_names = available.map(&:to_s) 80 81 # Get rid of invalid versions. Due to Gem::Version having a custom == 82 # method, which treats "3.4" the same as "3.4.0" we'll have to compare 83 # the versions as String instances. 84 versions = versions.select do |version| 85 available_names.include?(version.to_s) 86 end 87 88 versions = [available.last] if versions.empty? 89 90 versions 91 end