Extract local storage provider

This commit is contained in:
Ville Lautanala 2015-02-22 11:58:22 +02:00
parent 4f068c0ea1
commit 72f30e086d
13 changed files with 1 additions and 553 deletions

View File

@ -68,6 +68,7 @@ Gem::Specification.new do |s|
s.add_dependency("fog-atmos")
s.add_dependency("fog-serverlove")
s.add_dependency("fog-riakcs")
s.add_dependency("fog-local")
# Disabled until Rackspace isn't broken, see fog-rackspace#10
#s.add_dependency("fog-rackspace")

View File

@ -1,29 +0,0 @@
class Local < Fog::Bin
class << self
def class_for(key)
case key
when :storage
Fog::Storage::Local
else
raise ArgumentError, "Unsupported #{self} service: #{key}"
end
end
def [](service)
@@connections ||= Hash.new do |hash, key|
hash[key] = case key
when :storage
Fog::Logger.warning("Local[:storage] is not recommended, use Storage[:local] for portability")
Fog::Storage.new(:provider => 'Local')
else
raise ArgumentError, "Unrecognized service: #{key.inspect}"
end
end
@@connections[service]
end
def services
Fog::Local.services
end
end
end

View File

@ -1 +0,0 @@
require 'fog/local/storage'

View File

@ -1,9 +0,0 @@
require 'fog/core'
module Fog
module Local
extend Fog::Provider
service(:storage, 'Storage')
end
end

View File

@ -1,33 +0,0 @@
require 'fog/core/collection'
require 'fog/local/models/storage/directory'
module Fog
module Storage
class Local
class Directories < Fog::Collection
model Fog::Storage::Local::Directory
def all
data = if ::File.directory?(service.local_root)
Dir.entries(service.local_root).select do |entry|
entry[0...1] != '.' && ::File.directory?(service.path_to(entry))
end.map do |entry|
{:key => entry}
end
else
[]
end
load(data)
end
def get(key, options = {})
if ::File.directory?(service.path_to(key))
new(:key => key)
else
nil
end
end
end
end
end
end

View File

@ -1,53 +0,0 @@
require 'fog/core/model'
require 'fog/local/models/storage/files'
module Fog
module Storage
class Local
class Directory < Fog::Model
identity :key
def destroy
requires :key
if ::File.directory?(path)
Dir.rmdir(path)
true
else
false
end
end
def files
@files ||= begin
Fog::Storage::Local::Files.new(
:directory => self,
:service => service
)
end
end
def public=(new_public)
new_public
end
def public_url
nil
end
def save
requires :key
FileUtils.mkpath(path)
true
end
private
def path
service.path_to(key)
end
end
end
end
end

View File

@ -1,132 +0,0 @@
require 'fileutils'
require 'fog/core/model'
module Fog
module Storage
class Local
class File < Fog::Model
identity :key, :aliases => 'Key'
attribute :content_length, :aliases => 'Content-Length', :type => :integer
# attribute :content_type, :aliases => 'Content-Type'
attribute :last_modified, :aliases => 'Last-Modified'
require 'uri'
def body
attributes[:body] ||= if last_modified
collection.get(identity).body
else
''
end
end
def body=(new_body)
attributes[:body] = new_body
end
def content_type
@content_type ||= begin
unless (mime_types = ::MIME::Types.of(key)).empty?
mime_types.first.content_type
end
end
end
def directory
@directory
end
def copy(target_directory_key, target_file_key, options={})
requires :directory, :key
service.copy_object(directory.key, key, target_directory_key, target_file_key)
target_directory = service.directories.new(:key => target_directory_key)
target_directory.files.get(target_file_key)
end
def destroy
requires :directory, :key
::File.delete(path) if ::File.exist?(path)
dirs = path.split(::File::SEPARATOR)[0...-1]
dirs.length.times do |index|
dir_path = dirs[0..-index].join(::File::SEPARATOR)
if dir_path.empty? # path starts with ::File::SEPARATOR
next
end
# don't delete the containing directory or higher
if dir_path == service.path_to(directory.key)
break
end
pwd = Dir.pwd
if ::File.exist?(dir_path) && ::File.directory?(dir_path)
Dir.chdir(dir_path)
if Dir.glob('*').empty?
Dir.rmdir(dir_path)
end
Dir.chdir(pwd)
end
end
true
end
def public=(new_public)
new_public
end
def public_url
requires :directory, :key
if service.endpoint
escaped_directory = URI.escape(directory.key)
escaped_key = URI.escape(key)
::File.join(service.endpoint, escaped_directory, escaped_key)
else
nil
end
end
def save(options = {})
requires :body, :directory, :key
dirs = path.split(::File::SEPARATOR)[0...-1]
dirs.length.times do |index|
dir_path = dirs[0..index].join(::File::SEPARATOR)
if dir_path.empty? # path starts with ::File::SEPARATOR
next
end
# create directory if it doesn't already exist
begin
Dir.mkdir(dir_path)
rescue Errno::EEXIST
raise unless ::File.directory?(dir_path)
end
end
file = ::File.new(path, 'wb')
if body.is_a?(String)
file.write(body)
elsif body.kind_of? ::File and ::File.exist?(body.path)
FileUtils.cp(body.path, path)
else
file.write(body.read)
end
file.close
merge_attributes(
:content_length => Fog::Storage.get_body_size(body),
:last_modified => ::File.mtime(path)
)
true
end
private
def directory=(new_directory)
@directory = new_directory
end
def path
service.path_to(::File.join(directory.key, key))
end
end
end
end
end

View File

@ -1,84 +0,0 @@
require 'fog/core/collection'
require 'fog/local/models/storage/file'
module Fog
module Storage
class Local
class Files < Fog::Collection
attribute :directory
model Fog::Storage::Local::File
def all
requires :directory
if directory.collection.get(directory.key)
data = []
Dir.chdir(service.path_to(directory.key)) {
data = Dir.glob('**/*').reject do |file|
::File.directory?(file)
end.map do |key|
path = file_path(key)
{
:content_length => ::File.size(path),
:key => key,
:last_modified => ::File.mtime(path)
}
end
}
load(data)
else
nil
end
end
def get(key, &block)
requires :directory
path = file_path(key)
if ::File.exist?(path)
data = {
:content_length => ::File.size(path),
:key => key,
:last_modified => ::File.mtime(path)
}
if block_given?
file = ::File.open(path)
while (chunk = file.read(Excon::CHUNK_SIZE)) && yield(chunk); end
file.close
new(data)
else
body = ::File.read(path)
new(data.merge!(:body => body))
end
else
nil
end
end
def head(key)
requires :directory
path = file_path(key)
if ::File.exist?(path)
new({
:content_length => ::File.size(path),
:key => key,
:last_modified => ::File.mtime(path)
})
else
nil
end
end
def new(attributes = {})
requires :directory
super({ :directory => directory }.merge!(attributes))
end
private
def file_path(key)
service.path_to(::File.join(directory.key, key))
end
end
end
end
end

View File

@ -1,96 +0,0 @@
require 'fog/local/core'
module Fog
module Storage
class Local < Fog::Service
requires :local_root
recognizes :endpoint, :scheme, :host, :port, :path
model_path 'fog/local/models/storage'
collection :directories
model :directory
model :file
collection :files
require 'uri'
class Mock
attr_reader :endpoint
def self.data
@data ||= Hash.new do |hash, key|
hash[key] = {}
end
end
def self.reset
@data = nil
end
def initialize(options={})
Fog::Mock.not_implemented
@local_root = ::File.expand_path(options[:local_root])
@endpoint = options[:endpoint] || build_endpoint_from_options(options)
end
def data
self.class.data[@local_root]
end
def local_root
@local_root
end
def path_to(partial)
::File.join(@local_root, partial)
end
def reset_data
self.class.data.delete(@local_root)
end
private
def build_endpoint_from_options(options)
return unless options[:host]
URI::Generic.build(options).to_s
end
end
class Real
attr_reader :endpoint
def initialize(options={})
@local_root = ::File.expand_path(options[:local_root])
@endpoint = options[:endpoint] || build_endpoint_from_options(options)
end
def local_root
@local_root
end
def path_to(partial)
::File.join(@local_root, partial)
end
def copy_object(source_directory_name, source_object_name, target_directory_name, target_object_name, options={})
require 'fileutils'
source_path = path_to(::File.join(source_directory_name, source_object_name))
target_path = path_to(::File.join(target_directory_name, target_object_name))
::FileUtils.mkdir_p(::File.dirname(target_path))
::FileUtils.copy_file(source_path, target_path)
end
private
def build_endpoint_from_options(options)
return unless options[:host]
URI::Generic.build(options).to_s
end
end
end
end
end

View File

@ -1,17 +0,0 @@
Shindo.tests('Storage[:local] | directories', ["local"]) do
pending if Fog.mocking?
@options = { :local_root => "/tmp/fogtests" }
@collection = Fog::Storage::Local.new(@options).directories
collection_tests(@collection, {:key => "fogdirtests"}, true)
tests("#all") do
tests("succeeds when :local_root does not exist").succeeds do
FileUtils.rm_rf(@options[:local_root])
@collection.all
end
end
end

View File

@ -1,16 +0,0 @@
Shindo.tests('Storage[:local] | directory', ["local"]) do
pending if Fog.mocking?
before do
@options = { :local_root => '~/.fog' }
end
tests('save') do
returns(true) do
connection = Fog::Storage::Local.new(@options)
connection.directories.create(:key => 'directory')
connection.directories.create(:key => 'directory')
end
end
end

View File

@ -1,43 +0,0 @@
Shindo.tests('Storage[:local] | file', ["local"]) do
pending if Fog.mocking?
before do
@options = { :local_root => '~/.fog' }
end
tests('#public_url') do
tests('when connection has an endpoint').
returns('http://example.com/files/directory/file.txt') do
@options[:endpoint] = 'http://example.com/files'
connection = Fog::Storage::Local.new(@options)
directory = connection.directories.new(:key => 'directory')
file = directory.files.new(:key => 'file.txt')
file.public_url
end
tests('when connection has no endpoint').
returns(nil) do
@options[:endpoint] = nil
connection = Fog::Storage::Local.new(@options)
directory = connection.directories.new(:key => 'directory')
file = directory.files.new(:key => 'file.txt')
file.public_url
end
tests('when file path has escapable characters').
returns('http://example.com/files/my%20directory/my%20file.txt') do
@options[:endpoint] = 'http://example.com/files'
connection = Fog::Storage::Local.new(@options)
directory = connection.directories.new(:key => 'my directory')
file = directory.files.new(:key => 'my file.txt')
file.public_url
end
end
end

View File

@ -1,40 +0,0 @@
Shindo.tests('Local | storage') do
pending if Fog.mocking?
before do
@options = { :local_root => "~/.fog" }
end
tests('#endpoint') do
tests('when no endpoint is provided').
returns(nil) do
Fog::Storage::Local.new(@options).endpoint
end
tests('when no host is provided').
returns(nil) do
@options[:scheme] = 'http'
@options[:path] = '/files'
@options[:port] = 80
Fog::Storage::Local.new(@options).endpoint
end
tests('when endpoint is provided').
returns('http://example.com/files') do
@options[:endpoint] = 'http://example.com/files'
Fog::Storage::Local.new(@options).endpoint
end
tests('when at least host option is provided').
returns('http://example.com/files') do
@options[:scheme] = 'http'
@options[:host] = 'example.com'
@options[:path] = '/files'
Fog::Storage::Local.new(@options).endpoint
end
end
end