1
0
Fork 0
mirror of https://github.com/fog/fog.git synced 2022-11-09 13:51:43 -05:00

Merge pull request #1565 from rackspace/file_metadata

[Rackspace|Storage] Updated File to use the same Metadata class as Directory
This commit is contained in:
Kyle Rames 2013-02-27 06:35:42 -08:00
commit 3aaa584a88
8 changed files with 195 additions and 125 deletions

View file

@ -27,7 +27,7 @@ module Fog
end
end
directory.metadata = Metadata.from_headers(data.headers)
directory.metadata = Metadata.from_headers(directory, data.headers)
directory.files.merge_attributes(options)
directory.files.instance_variable_set(:@loaded, true)

View file

@ -18,19 +18,19 @@ module Fog
def metadata=(hash)
if hash.is_a? Fog::Storage::Rackspace::Metadata
@metadata = hash
attributes[:metadata] = hash
else
@metadata = Fog::Storage::Rackspace::Metadata.new(hash)
attributes[:metadata] = Fog::Storage::Rackspace::Metadata.new(self, hash)
end
@metadata
attributes[:metadata]
end
def metadata
unless @metadata
unless attributes[:metadata]
response = service.head_container(key)
@metadata = Fog::Storage::Rackspace::Metadata.from_headers(response.headers)
attributes[:metadata] = Fog::Storage::Rackspace::Metadata.from_headers(self, response.headers)
end
@metadata
attributes[:metadata]
end
def destroy
@ -81,7 +81,6 @@ module Fog
def save
requires :key
create_container
raise Fog::Storage::Rackspace::Error.new("Directory can not be set as :public without a CDN provided") if public? && !cdn_enabled?
@urls = service.cdn.publish_container(self, public?)
@ -101,7 +100,7 @@ module Fog
end
def create_container
headers = @metadata.nil? ? {} : metadata.to_headers
headers = attributes[:metadata].nil? ? {} : metadata.to_headers
service.put_container(key, headers)
end
end

View file

@ -17,6 +17,9 @@ module Fog
attr_writer :public
attr_accessor :directory
attr_writer :public
def body
attributes[:body] ||= if last_modified
collection.get(identity).body
@ -29,10 +32,6 @@ module Fog
attributes[:body] = new_body
end
def directory
@directory
end
def copy(target_directory_key, target_file_key, options={})
requires :directory, :key
options['Content-Type'] ||= content_type if content_type
@ -49,10 +48,19 @@ module Fog
true
end
def metadata
@metadata ||= headers_to_metadata
def metadata=(hash)
if hash.is_a? Fog::Storage::Rackspace::Metadata
attributes[:metadata] = hash
else
attributes[:metadata] = Fog::Storage::Rackspace::Metadata.new(self, hash)
end
attributes[:metadata]
end
def metadata
attributes[:metadata] ||= Fog::Storage::Rackspace::Metadata.new(self)
end
def owner=(new_owner)
if new_owner
attributes[:owner] = {
@ -91,71 +99,17 @@ module Fog
options['Content-Type'] = content_type if content_type
options['Access-Control-Allow-Origin'] = access_control_allow_origin if access_control_allow_origin
options['Origin'] = origin if origin
options.merge!(metadata_to_headers)
options.merge!(metadata.to_headers)
data = service.put_object(directory.key, key, body, options)
update_attributes_from(data)
refresh_metadata
self.content_length = Fog::Storage.get_body_size(body)
self.content_type ||= Fog::Storage.get_content_type(body)
true
end
private
def directory=(new_directory)
@directory = new_directory
end
def refresh_metadata
metadata.reject! {|k, v| v.nil? }
end
def headers_to_metadata
key_map = key_mapping
Hash[metadata_attributes.map {|k, v| [key_map[k], v] }]
end
def key_mapping
key_map = metadata_attributes
key_map.each_pair {|k, v| key_map[k] = header_to_key(k)}
end
def header_to_key(opt)
opt.gsub(metadata_prefix, '').split('-').map {|k| k[0, 1].downcase + k[1..-1]}.join('_').to_sym
end
def metadata_to_headers
hash = {}
metadata.each_pair do |k,v|
key = metakey(k,v)
hash[key] = v
end
hash
end
def metakey(key, value)
prefix = value.nil? ? "X-Remove-Object-Meta-" : "X-Object-Meta-"
prefix + key.to_s.split(/[-_]/).map(&:capitalize).join('-')
end
def metadata_attributes
if last_modified
headers = service.head_object(directory.key, self.key).headers
headers.reject! {|k, v| !metadata_attribute?(k)}
else
{}
end
end
def metadata_attribute?(key)
key.to_s =~ /^#{metadata_prefix}/
end
def metadata_prefix
"X-Object-Meta-"
end
private
def update_attributes_from(data)
merge_attributes(data.headers.reject {|key, value| ['Content-Length', 'Content-Type'].include?(key)})

View file

@ -55,10 +55,13 @@ module Fog
def get(key, &block)
requires :directory
data = service.get_object(directory.key, key, &block)
metadata = Metadata.from_headers(data.headers)
file_data = data.headers.merge({
:body => data.body,
:key => key
:key => key,
:metadata => metadata
})
new(file_data)
rescue Fog::Storage::Rackspace::NotFound
nil

View file

@ -4,21 +4,24 @@ module Fog
class Metadata
# META_PREFIX = "X-Object-Meta-"
# REMOVE_META_PREFIX = "X-Remove-Object-Meta-"
META_PREFIX = "X-Container-Meta-"
REMOVE_META_PREFIX = "X-Remove-Container-Meta-"
OBJECT_META_PREFIX = "X-Object-Meta-"
OBJECT_REMOVE_META_PREFIX = "X-Remove-Object-Meta-"
CONTAINER_META_PREFIX = "X-Container-Meta-"
CONTAINER_REMOVE_META_PREFIX = "X-Remove-Container-Meta-"
# Cloud Files will ignore headers without a value
DUMMY_VALUE = 1
KEY_REGEX = /^#{META_PREFIX}(.*)/
CONTAINER_KEY_REGEX = /^#{CONTAINER_META_PREFIX}(.*)/
OBJECT_KEY_REGEX = /^#{OBJECT_META_PREFIX}(.*)/
attr_reader :data
def initialize(hash={})
attr_reader :data, :parent
def initialize(parent, hash={})
@data = hash || {}
@deleted_hash = {}
@parent = parent
end
def delete(key)
@ -37,10 +40,10 @@ module Fog
headers
end
def self.from_headers(headers)
metadata = Metadata.new
def self.from_headers(parent, headers)
metadata = Metadata.new(parent)
headers.each_pair do |k, v|
key = Metadata.to_key(k)
key = metadata.send(:to_key, k)
next unless key
metadata.data[key] = v
end
@ -57,8 +60,38 @@ module Fog
private
def self.to_key(key)
m = key.match KEY_REGEX
def meta_prefix
if parent.is_a? Fog::Storage::Rackspace::Directory
CONTAINER_META_PREFIX
elsif parent.is_a? Fog::Storage::Rackspace::File
OBJECT_META_PREFIX
else
raise "Metadata prefix is unknown for #{parent.class}"
end
end
def remove_meta_prefix
if parent.is_a? Fog::Storage::Rackspace::Directory
CONTAINER_REMOVE_META_PREFIX
elsif parent.is_a? Fog::Storage::Rackspace::File
OBJECT_REMOVE_META_PREFIX
else
raise "Remove Metadata prefix is unknown for #{parent.class}"
end
end
def meta_prefix_regex
if parent.is_a? Fog::Storage::Rackspace::Directory
CONTAINER_KEY_REGEX
elsif parent.is_a? Fog::Storage::Rackspace::File
OBJECT_KEY_REGEX
else
raise "Metadata prefix is unknown for #{parent.class}"
end
end
def to_key(key)
m = key.match meta_prefix_regex
return nil unless m && m[1]
a = m[1].split('-')
@ -68,7 +101,7 @@ module Fog
end
def to_header_key(key, value)
prefix = value.nil? ? REMOVE_META_PREFIX : META_PREFIX
prefix = value.nil? ? remove_meta_prefix : meta_prefix
prefix + key.to_s.split(/[-_]/).collect(&:capitalize).join('-')
end

View file

@ -96,8 +96,9 @@ Shindo.tests('Fog::Rackspace::Storage | directory', ['rackspace']) do
pending if Fog.mocking?
model_tests(@service.directories, directory_attributes, Fog.mocking?) do
tests('sets metadata on create').returns({:draft => 'true'}) do
tests('sets metadata on create').returns('true') do
@instance.metadata.data
container_meta_attributes["X-Container-Meta-Draft"]
end
tests('update metadata').returns({"X-Container-Meta-Draft"=>"true", "X-Container-Meta-Color"=>"green"}) do
@instance.metadata[:color] = 'green'
@ -122,6 +123,18 @@ Shindo.tests('Fog::Rackspace::Storage | directory', ['rackspace']) do
returns('true') { dir.metadata[:list_test] }
end
tests("should reload metadata after calling reload").returns("42") do
@service.put_container @instance.key, "X-Container-Meta-Answer" => 42
@instance.reload
@instance.metadata[:answer]
end
tests("should reload metadata after calling reload").returns("42") do
@service.put_container @instance.key, "X-Container-Meta-Answer" => 42
@instance.reload
@instance.metadata[:answer]
end
end
end

View file

@ -2,8 +2,8 @@ Shindo.tests('Fog::Rackspace::Storage | file', ['rackspace']) do
pending if Fog.mocking?
def object_meta_attributes
@instance.service.head_object(@directory.key, @instance.key).headers.reject {|k, v| !(k =~ /X-Object-Meta-/)}
def object_meta_attributes(file=@instance)
@instance.service.head_object(@directory.key, file.key).headers.reject {|k, v| !(k =~ /X-Object-Meta-/)}
end
def clear_metadata
@ -35,7 +35,7 @@ Shindo.tests('Fog::Rackspace::Storage | file', ['rackspace']) do
model_tests(@directory.files, file_attributes, Fog.mocking?) do
tests("#metadata should load empty metadata").returns({}) do
@instance.metadata
@instance.metadata.data
end
tests('#save') do
@ -79,6 +79,15 @@ Shindo.tests('Fog::Rackspace::Storage | file', ['rackspace']) do
end
end
end
begin
tests("sets metadata on create").returns("true") do
@file = @directory.files.create :key => 'meta-test', :body => lorem_file, :metadata => {:works => true }
object_meta_attributes(@file)["X-Object-Meta-Works"]
end
ensure
@file.destroy if @file
end
tests('urls') do
tests('no CDN') do

View file

@ -1,35 +1,40 @@
require 'fog/rackspace/models/storage/metadata'
require 'fog/rackspace/models/storage/directory'
require 'fog/rackspace/models/storage/file'
Shindo.tests('Fog::Rackspace::Storage | metadata', ['rackspace']) do
tests('#to_key') do
tests('valid key').returns(:image_size) do
Fog::Storage::Rackspace::Metadata.send(:to_key, "X-Container-Meta-Image-Size")
tests('Directory') do
@directory = Fog::Storage::Rackspace::Directory.new
tests('#to_key') do
tests('valid key').returns(:image_size) do
metadata = Fog::Storage::Rackspace::Metadata.new @directory
metadata.send(:to_key, "X-Container-Meta-Image-Size")
end
tests('invalid key').returns(nil) do
metadata = Fog::Storage::Rackspace::Metadata.new @directory
metadata.send(:to_key, "bad-key")
end
end
tests('invalid key').returns(nil) do
Fog::Storage::Rackspace::Metadata.send(:to_key, "bad-key")
end
end
tests('#to_header_key') do
metadata = Fog::Storage::Rackspace::Metadata.new
tests('#to_header_key') do
metadata = Fog::Storage::Rackspace::Metadata.new @directory
tests('key to add').returns("X-Container-Meta-Thumbnail-Image") do
metadata.send(:to_header_key, :thumbnail_image, true)
tests('key to add').returns("X-Container-Meta-Thumbnail-Image") do
metadata.send(:to_header_key, :thumbnail_image, true)
end
tests('key to remove').returns("X-Remove-Container-Meta-Thumbnail-Image") do
metadata.send(:to_header_key, :thumbnail_image, nil)
end
end
tests('key to remove').returns("X-Remove-Container-Meta-Thumbnail-Image") do
metadata.send(:to_header_key, :thumbnail_image, nil)
end
end
tests('#to_headers').returns({"X-Container-Meta-Preview"=>true, "X-Remove-Container-Meta-Delete-Me"=>1}) do
metadata = Fog::Storage::Rackspace::Metadata.new
metadata[:preview] = true
metadata[:delete_me] = nil
tests('#to_headers').returns({"X-Container-Meta-Preview"=>true, "X-Remove-Container-Meta-Delete-Me"=>1}) do
metadata = Fog::Storage::Rackspace::Metadata.new @directory
metadata[:preview] = true
metadata[:delete_me] = nil
metadata.to_headers
end
metadata.to_headers
end
tests("#from_headers").returns({:my_boolean=>"true", :my_integer=>"42", :my_string=>"I am a string"}) do
headers = {
@ -38,30 +43,84 @@ Shindo.tests('Fog::Rackspace::Storage | metadata', ['rackspace']) do
"X-Container-Meta-My-String"=> "I am a string"
}
metadata = Fog::Storage::Rackspace::Metadata.from_headers headers
metadata.data
end
metadata = Fog::Storage::Rackspace::Metadata.from_headers @directory, headers
metadata.data
end
tests("#delete").returns({"X-Remove-Container-Meta-Delete-Me"=>1}) do
metadata = Fog::Storage::Rackspace::Metadata.new
metadata.delete(:delete_me)
tests("#delete").returns({"X-Remove-Container-Meta-Delete-Me"=>1}) do
metadata = Fog::Storage::Rackspace::Metadata.new @directory
metadata.delete(:delete_me)
metadata.to_headers
metadata.to_headers
end
end
tests('File') do
@file = Fog::Storage::Rackspace::File.new
tests('#to_key') do
tests('valid key').returns(:image_size) do
metadata = Fog::Storage::Rackspace::Metadata.new @file
metadata.send(:to_key, "X-Object-Meta-Image-Size")
end
tests('invalid key').returns(nil) do
metadata = Fog::Storage::Rackspace::Metadata.new @file
metadata.send(:to_key, "bad-key")
end
end
tests('#to_header_key') do
metadata = Fog::Storage::Rackspace::Metadata.new @file
tests('key to add').returns("X-Object-Meta-Thumbnail-Image") do
metadata.send(:to_header_key, :thumbnail_image, true)
end
tests('key to remove').returns("X-Remove-Object-Meta-Thumbnail-Image") do
metadata.send(:to_header_key, :thumbnail_image, nil)
end
end
tests('#to_headers').returns({"X-Object-Meta-Preview"=>true, "X-Remove-Object-Meta-Delete-Me"=>1}) do
metadata = Fog::Storage::Rackspace::Metadata.new @file
metadata[:preview] = true
metadata[:delete_me] = nil
metadata.to_headers
end
tests("#from_headers").returns({:my_boolean=>"true", :my_integer=>"42", :my_string=>"I am a string"}) do
headers = {
"X-Object-Meta-My-Integer"=> "42",
"X-Object-Meta-My-Boolean"=> "true",
"X-Object-Meta-My-String"=> "I am a string"
}
metadata = Fog::Storage::Rackspace::Metadata.from_headers @file, headers
metadata.data
end
tests("#delete").returns({"X-Remove-Object-Meta-Delete-Me"=>1}) do
metadata = Fog::Storage::Rackspace::Metadata.new @file
metadata.delete(:delete_me)
metadata.to_headers
end
end
tests("#respond_to?") do
tests('Should respond to all of the methods in Hash class').returns(true) do
metadata = Fog::Storage::Rackspace::Metadata.new
metadata = Fog::Storage::Rackspace::Metadata.new @file
Hash.instance_methods.all? {|method| metadata.respond_to?(method)}
end
tests('Should respond to all of the methods in the Metadata class').returns(true) do
metadata = Fog::Storage::Rackspace::Metadata.new
metadata = Fog::Storage::Rackspace::Metadata.new @file
metadata.methods.all? {|method| metadata.respond_to?(method)}
end
end
tests("#method_missing").returns(true) do
metadata = Fog::Storage::Rackspace::Metadata.new
metadata = Fog::Storage::Rackspace::Metadata.new @file
metadata[:test] = true
metadata[:test]
end