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

source[R]
versions_file[R]

Public Class Methods

new(source, versions_file) click to toggle source

@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

assign_gem_versions(gems) click to toggle source

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
configuration() click to toggle source

@see GemMirror.configuration

    # File lib/gem_mirror/gems_fetcher.rb
233 def configuration
234   GemMirror.configuration
235 end
dependencies_for(spec) click to toggle source

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
fetch() click to toggle source

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
fetch_dependencies(deps) click to toggle source

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
fetch_gem(gem, version) click to toggle source

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
fetch_specification(gem, version) click to toggle source

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
filter_dependencies(possible_dependencies) click to toggle source

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
gem_exists?(filename) click to toggle source

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
ignore_gem?(*args) click to toggle source

@see GemMirror::Configuration#ignore_gem?

    # File lib/gem_mirror/gems_fetcher.rb
250 def ignore_gem?(*args)
251   configuration.ignore_gem?(*args)
252 end
load_specification(raw_spec) click to toggle source

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
logger() click to toggle source

@see GemMirror::Configuration#logger @return [Logger]

    # File lib/gem_mirror/gems_fetcher.rb
226 def logger
227   configuration.logger
228 end
versions_for(gem) click to toggle source

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