lib/repertoire/media/media.rb in repertoire-0.1.0 vs lib/repertoire/media/media.rb in repertoire-0.1.1

- old
+ new

@@ -1,134 +1,242 @@ require 'repertoire/media/exceptions/unknown_media' -require 'repertoire/media/exceptions/program_not_found' +require 'repertoire/media/exceptions/repository_exists' +require 'repertoire/media/exceptions/checkout_failed' +require 'repertoire/media/exceptions/update_failed' require 'repertoire/extensions/uri' -require 'repertoire/compat' require 'fileutils' module Repertoire - class Media - + module Media # - # Returns the Hash of all registered Media types. + # Returns the +Hash+ of all registered Media types. # def Media.types - @types ||= {} + @@media_types ||= {} end # - # Returns +true+ if a Media type was registered for the specified - # _scheme_, returns +false+ otherwise. + # Returns +true+ if there is a Media type registered with the matching + # _name_. # - def Media.supported?(scheme) - Media.types.has_key?(scheme.to_s) + def Media.supports?(name) + Media.types.has_key?(name.to_sym) end # - # Get the Media type that was registered for the specified _scheme_. + # Returns the Media type with the matching _name_. # - def Media.get(scheme) - unless Media.supported?(scheme) - raise(UnknownMedia,"media type #{scheme.dump} is unsupported",caller) + def Media.get(name) + name = name.to_sym + + unless Media.supports?(name) + raise(UnknownMedia,"media type #{name.dump} is not registered",caller) end - return Media.types[scheme] + return Media.types[name] end # - # Get the Media type that was registered for the scheme of the - # specified _uri_. + # Returns the +Hash+ of all registered Media types and their associated + # URI schemes. # - def Media.get_for_uri(uri) - Media.get(URI.parse(uri).scheme) + def Media.schemes + @@media_schemes ||= {} end # - # Attempts to determine the correct Media type for the specified _path_. + # Returns an +Array+ of all registered URI schemes. # - def Media.guess(path) - path = File.expand_path(path) + def Media.registered_schemes + Media.schemes.keys + end - Media.types.values.uniq.each do |media| - if media.respond_to?(:is_repo?) - return media if media.is_repo?(path) - end + # + # Returns +true+ if a Media type was registered for the specified + # _scheme_, returns +false+ otherwise. + # + def Media.supports_scheme?(scheme) + Media.schemes.has_key?(scheme.to_s) + end + + # + # Returns the Media type that was registered for the specified _scheme_. + # + def Media.supports_scheme(name) + name = name.to_s + + unless Media.supports_scheme?(name) + raise(UnknownMedia,"media type for scheme #{name.dump} is not registered",caller) end - raise(UnknownMedia,"the media type for #{path.dump} is unknown",caller) + return Media.schemes[name] end # - # Checkout the repository at the specified _uri_ and the given _path_. + # Returns the +Hash+ of all registered Media types and their + # associated media storage directories. # - def Media.checkout(uri,path=nil) - if path - path = File.expand_path(path) - else - path = URI.repo_name(uri) - end + def Media.directories + @@media_directories ||= {} + end - return Media.get_for_uri(uri).checkout(uri,path) + # + # Returns an +Array+ of all registered directories. + # + def Media.registered_directories + Media.directories.keys end # - # Update the repository at the specified _path_ and the given _uri_. - # If _uri_ is not given Repertoire will attempt to guess the media - # type of the repository, see Media.guess. + # Returns +true+ if a Media type was registered with the specified + # _directory_, returns +false+ otherwise. # - def Media.update(path,uri=nil) - path = File.expand_path(path) + def Media.recognizes_directory?(name) + Media.directories.has_key?(name.to_s) + end - if uri.nil? - media = Media.guess(path) - else - media = Media.get_for_uri(uri) + # + # Returns the Media type that was registered for the specified + # _directory_. + # + def Media.recognizes_directory(name) + name = name.to_s + + unless Media.recognizes_directory?(name) + raise(UnknownMedia,"media type for directory #{name.dump} is not registered",caller) end - return media.update(path,uri) + return Media.directories[name] end # - # Delete the repository at the specified _path_. + # Get the Media type that was registered for the scheme of the + # specified _uri_. # - def Media.delete(path) - FileUtils.rm_r(path.to_s,:force => true, :secure => true) + def Media.guess_from_uri(uri) + scheme = URI(uri).scheme + + return [scheme, Media.supports_scheme(scheme)] end - protected + # + # Attempts to determine the correct Media type for the specified _path_. + # + def Media.guess_from_path(path) + path = File.expand_path(path) + Media.directories.each do |directory,media| + if File.directory?(File.join(path,directory)) + return media + end + end + + raise(UnknownMedia,"the media type for #{path.dump} is unknown",caller) + end + # - # Register a Media type for the specified _schemes_. + # Checkout the repository at the specified _options_. If a _block_ + # is given, it will be passed the path of the local repository + # after the repository is successfully checked out. # - # uses_schemes 'cvs' + # _options_ must contain the following key: + # <tt>:uri</tt>:: The URI of the repository to checkout. # - # uses_schemes 'svn', 'svn+ssh' + # _options_ may also contain the additional keys: + # <tt>:path</tt>:: Path to checkout the repository to. + # <tt>:media</tt>:: The media type of the repository. Defaults to the + # value of Media.get_for_uri. + # <tt>:into</tt>:: Checkout the repository into the given directory. + # Cannot be used with <tt>:path</tt>. # - def self.uses_schemes(*schemes) - schemes.each do |scheme| - Media.types[scheme.to_s] = self + def Media.checkout(options={},&block) + uri = options[:uri].to_s + path = options[:path] + into = options[:into] + media = options[:media] + + unless path + if into + into = File.expand_path(into) + + unless File.directory?(into) + FileUtils.mkdir_p(into) + end + + path = File.join(into,URI.repo_name(uri)) + else + path = URI.repo_name(uri) + end end + + path = File.expand_path(path) + if File.exists?(path) + raise(RepositoryExists,"the repository #{path.dump} already exists",caller) + end + + if media + handler = Media.get(media) + else + media, handler = Media.guess_from_uri(uri) + end + + begin + handler.checkout(uri,path) + rescue CommandFailed + raise(CheckoutFailed,"failed to checkout the repository located at #{uri.dump}",caller) + end + + block.call(path,media,uri) if block + return {:path => path, :media => media, :uri => uri} end # - # Runs the command specified by _program_ and the given _args_. - # If _program_ cannot be found on the system, a ProgramNotFound - # exception will be raised. + # Update the repository with the specified _options_. If a _block_ + # is given, it will be passed the path of the local repository + # after the repository is successfully updated. # - # sh('ls','-la','/') + # _options_ must contain the following keys: + # <tt>:path</tt>:: The path of the repository to update. # - def self.sh(program,*args) - program = program.to_s + # _options_ may also contain the additional keys: + # <tt>:uri</tt>:: The URI to update against. + # <tt>:media</tt>:: The type of the repository. Defaults to + # Media.guess_from_uri if <tt>:uri</tt> is given, + # otherwise Media.guess_from_path. + # + def Media.update(options={},&block) + path = File.expand_path(options[:path]) + uri = options[:uri] + media = options[:media] - program_path = Compat.find_program(program) - unless program_path - raise(ProgramNotFound,"the program #{program.dump} was not found",caller) + if media + handler = Media.get(media) + elsif uri + media, handler = Media.guess_from_uri(uri) + else + handler = Media.guess_from_path(path) end - # stringify the args - args = args.map { |arg| arg.to_s } + begin + handler.update(path,uri) + rescue CommandFailed + raise(UpdateFailed,"failed to update the repository at #{path.dump}",caller) + end - return system(program_path,*args) + block.call(media,path,uri) if block + return {:media => media, :path => path, :uri => uri} end + # + # Delete the repository at the specified _path_. If a _block_ is + # given, it will be passed the _path_ before it is deleted. + # + def Media.delete(path,&block) + path = File.expand_path(path) + + block.call(path) if block + FileUtils.rm_r(path.to_s,:force => true, :secure => true) + return nil + end end end