lib/omnibus/fetcher.rb in omnibus-3.2.2 vs lib/omnibus/fetcher.rb in omnibus-4.0.0.beta.1

- old
+ new

@@ -12,176 +12,135 @@ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. # -require 'pp' - module Omnibus - # Base class for classes that fetch project sources from the internet. - # - # @abstract Subclass and override the {#clean}, {#description}, - # {#fetch}, {#fetch_required?}, and {#version_guid} methods - # - # @todo Is this class supposed to be abstract or not? Pretty sure - # it's supposed to be abstract class Fetcher - # Given an error and a fetcher that generated the error, print a - # formatted report of the error and stacktrace, along with fetcher - # details to stderr. + include Digestable + include Logging + include Util + # - # @note Does not rethrow the error; that must currently be done manually. + # The software for this fetcher. # - # @todo Since this is always called from within a fetcher, and - # since the fetcher always passes itself in in the {#initialize} - # method, this really ought to be encapsulated in a method call on - # {Omnibus::Fetcher}. - # @todo Also, since we always 'raise' after calling {#explain}, we - # should just go ahead and exit from here. No need to raise, - # since we're already outputting the real error and stacktrace - # here. - class ErrorReporter - def initialize(error, fetcher) - @error, @fetcher = error, fetcher - end - - # @todo Why not just make an attribute for error? - # - # @todo And for that matter, why not make an attribute for the - # fetcher as well? Or why not just use `@error` like we use - # `@fetcher`? - def e - @error - end - - # @todo If {Omnibus::Fetcher#description} is meant to show - # parameters (presumably the kind of fetcher and the software it - # is fetching?), - # @todo make this use the logger - def explain(why) - $stderr.puts '* ' * 40 - $stderr.puts why - $stderr.puts 'Fetcher params:' - $stderr.puts indent(@fetcher.description, 2) - $stderr.puts 'Exception:' - $stderr.puts indent("#{e.class}: #{e.message.strip}", 2) - Array(e.backtrace).each { |l| $stderr.puts indent(l, 4) } - $stderr.puts '* ' * 40 - end - - private - - # Indent each line of a string with `n` spaces. - # - # Splits the string at `\n` characters and then pads the left - # side with `n` spaces. Rejoins them all again with `\n`. - # - # @param string [String] the string to indent - # @param n [Fixnum] the number of " " characters to indent each line. - # @return [String] - def indent(string, n) - string.split("\n").map { |l| ' '.rjust(n) << l }.join("\n") - end - end - - class UnsupportedSourceLocation < ArgumentError - end - - NULL_ARG = Object.new - - # Returns an implementation of {Fetcher} that can retrieve the - # given software. + # @return [Software] # - # @param software [Omnibus::Software] the software the Fetcher should fetch - # @return [Omnibus::Fetcher] - def self.for(software) - if software.source - if software.source[:url] && Config.use_s3_caching - S3CacheFetcher.new(software) - else - without_caching_for(software) - end - else - Fetcher.new(software) - end - end + attr_reader :software - # @param software [Omnibus::Software] the software to fetch - # @raise [UnsupportedSourceLocation] if the software's source is not - # one of `:url`, `:git`, or `:path` - # @see Omnibus::Software#source - # @todo Define an enumeration of the acceptable software types - # @todo This probably ought to be folded into {#for} method above. - # It looks like this is called explicitly in - # {Omnibus::S3Cache#fetch}, but that could be handled by having a - # second optional parameter that always disables caching. - # @todo Since the software determines what fetcher must be used to - # fetch it, perhaps this should be a method on {Omnibus::Software} - # instead. - def self.without_caching_for(software) - if software.source[:url] - NetFetcher.new(software) - elsif software.source[:git] - GitFetcher.new(software) - elsif software.source[:path] - PathFetcher.new(software) - else - raise UnsupportedSourceLocation, "Don't know how to fetch software project #{software}" - end - end - - include Logging - include Util - - attr_reader :name - - # @todo What is this? It doesn't appear to be used anywhere - attr_reader :source_timefile - + # + # Create a new Fetcher object from the given software. + # + # @param [Software] software + # the software to create this fetcher + # def initialize(software) @software = software end - # @!group Methods for Subclasses to Implement + # + # @!group Abstract methods + # + # The following methods are all abstract and should be overriden in child + # classes. + # -------------------------------------------------- - # @todo All extenders of this class override this method. Since - # this class appears to be intended as an abstract one, this - # should raise a NotImplementedError - def description - # Not as pretty as we'd like, but it's a sane default: - inspect - end - - # @todo All extenders of this class override this method. Since - # this class appears to be intended as an abstract one, this - # should raise a NotImplementedError + # + # @abstract + # def fetch_required? - false + raise NotImplementedError end - # @todo Empty method is very suspicious; raise NotImplementedError instead. + # + # @abstract + # def clean + raise NotImplementedError end - # @todo Empty method is very suspicious; raise NotImplementedError instead. + # + # @abstract + # def fetch + raise NotImplementedError end - # @todo Empty method is very suspicious; raise NotImplementedError instead. + # + # @abstract + # def version_guid + raise NotImplementedError end - # Returns the version to be used during build caching. - # By default fetchers don't override the versions. + # + # @abstract + # def version_for_cache - nil + raise NotImplementedError end + # + # @!endgroup + # -------------------------------------------------- + private + # + # The "source" for this software, with applied overrides. + # + # @return [Hash] + # + def source + software.source + end + + # + # The path where extracted software should live. + # + # @see Software#project_dir + # + # @return [String] + # + def project_dir + software.project_dir + end + + # + # The version for this sfotware, with applied overrides. + # + # @return [String] + # + def version + software.version + end + + # + # Override the +log_key+ for this fetcher to include the name of the + # software during the fetch. + # + # @return [String] + # def log_key - @log_key ||= "#{super}: #{@software.name}" + @log_key ||= "#{super}: #{software.name}" end - # !@endgroup + + # + # Idempotently create the required directories for building/downloading. + # Fetchers should call this method before performing any operations that + # manipulate the filesystem. + # + # @return [void] + # + def create_required_directories + [ + Config.cache_dir, + Config.source_dir, + software.build_dir, + software.project_dir, + ].each do |directory| + FileUtils.mkdir_p(directory) unless File.directory?(directory) + end + end end end