Permalink
Browse files

added list_blobs

  • Loading branch information...
1 parent 1127de4 commit 8f3a83c5d263175739a1512ed00dd8a6bfdc544e @shadysayed committed Sep 10, 2012
@@ -5,6 +5,7 @@ module Fog
module Storage
class Azure
class Directories < Fog::Collection
+ include Fog::Storage::Azure::Utils
model Fog::Storage::Azure::Directory
attribute :next_marker, :aliases => ['NextMarker']
attribute :marker, :aliases => ["Marker"]
@@ -18,6 +19,27 @@ def all(options = {})
end
def get(key, options = {})
+ remap_attributes(options,{
+ delimiter: 'delimiter',
+ marker: 'marker',
+ prefix: 'prefix'
+ })
+ response = connection.list_blobs(key, options)
+ data = response.body
+ directory = new(key: key)
+ # copy what we know about into the files collection
+ options = extract_sub_dictionary(data,
+ 'BlobPrefixes',
+ 'Marker',
+ 'Delimiter',
+ 'NextMarker',
+ 'Prefix'
+ )
+ directory.files.merge_attributes(options)
+ directory.files.load(data['Content'])
+ directory
+ rescue Excon::Errors::NotFound
+ nil
end
alias :each_dir_this_page :each
@@ -9,6 +9,10 @@ class Directory < Fog::Model
attribute :url, :aliases => ['Url']
attribute :etag, :aliases => ['Etag']
attribute :metadata, :aliases => ['Metadata']
+
+ def files
+ @files ||= Fog::Storage::Azure::Files.new(directory: self, connection: connection)
+ end
end
end
end
@@ -0,0 +1,14 @@
+require 'fog/core/model'
+# require 'fog/azure/models/storage/version'
+
+module Fog
+ module Storage
+ class Azure
+ class File < Fog::Model
+
+ identity :key, :aliases => 'Name'
+
+ end
+ end
+ end
+end
@@ -0,0 +1,65 @@
+require 'fog/core/collection'
+require 'fog/azure/models/storage/file'
+
+module Fog
+ module Storage
+ class Azure
+ class Files < Fog::Collection
+ include Fog::Storage::Azure::Utils
+
+ attribute :blob_prefixes, :aliases=> ['BlobPrefixes']
+ attribute :delimiter, :aliases => 'Delimiter'
+ attribute :directory
+ attribute :marker, :aliases => 'Marker'
+ attribute :next_marker, :aliases => 'NextMarker'
+ attribute :max_results, :aliases => ["MaxResults"]
+ attribute :prefix, :aliases => ['Prefix']
+
+ alias :common_prefixes :blob_prefixes #Compatibility with AWS
+
+ model Fog::Storage::Azure::File
+
+ def all(options = {})
+ requires :directory
+ options = {
+ 'delimiter' => delimiter,
+ 'marker' => marker,
+ 'MaxResults' => max_results,
+ 'prefix' => prefix
+ }.merge! stringify_keys(options)
+ options = options.reject{ |key, value| value.nil? || value.to_s.empty? }
+ merge_attributes(options)
+
+ parent = directory.collection.get(
+ directory.key,
+ options
+ )
+ if parent
+ merge_attributes(parent.files.attributes)
+ load(parent.files.map{ |file| file.attributes })
+ else
+ nil
+ end
+ end
+
+ def get(key, options = {}, &block)
+
+ end
+
+ alias :each_file_this_page :each
+ def each
+ if block_given?
+ subset = dup.all
+ subset.each_file_this_page { |f| yield f }
+ while subset.next_marker != nil
+ subset = subset.all(marker: subset.next_marker)
+ subset.each_file_this_page { |f| yield f }
+ end
+ end
+ self
+ end
+
+ end
+ end
+ end
+end
@@ -0,0 +1,69 @@
+module Fog
+ module Parsers
+ module Storage
+ module Azure
+ class ListBlobs < Fog::Parsers::Base
+ def reset
+ @blob = {}
+ @response = {'Content' => [], 'BlobPrefixes' => []}
+ end
+
+ def start_element(name, attrs = [])
+ super
+ case name
+ when 'Blob'
+ @in_blob = true
+ when 'Metadata'
+ @in_metadata = true
+ @blob['Metadata'] ||= {}
+ when 'BlobPrefix'
+ @in_blob_prefix = true
+ end
+ end
+
+ def in_blob_directly?
+ in_blob? && !(@in_metadata || @in_blob_prefix)
+ end
+
+ def in_blob?
+ @in_blob
+ end
+
+ def in_root?
+ !(in_blob? || @in_blob_prefix)
+ end
+
+
+ def end_element(name)
+ case name
+ when "Blob"
+ unless @in_metadata
+ @response['Content'] << @blob
+ @blob = {}
+ @in_blob = false
+ end
+ when "Name", "Url", "Etag", "Snapshot", "Content-Type"
+ @blob[name] = value if in_blob_directly?
+ when "Last-Modified"
+ @blob[name] = Time.parse(value) if in_blob_directly?
+ when "Content-Length"
+ @blob[name] = value.to_i if in_blob_directly?
+ when "Prefix", "Marker", "NextMarker", "MaxResults", "Delimiter"
+ @response[name] = value if in_root?
+ when 'Metadata'
+ @in_metadata = false
+ when 'BlobPrefix'
+ @in_blob_prefix = false
+ end
+
+ if @in_metadata
+ @blob['Metadata'][name] = value
+ elsif @in_blob_prefix && name == 'Name'
+ @response['BlobPrefixes'] << value
+ end
+ end
+ end
+ end
+ end
+ end
+end
@@ -0,0 +1,32 @@
+module Fog
+ module Storage
+ class Azure
+ class Real
+ require 'fog/azure/parsers/storage/list_blobs'
+
+
+ def list_blobs(container_name, options = {})
+ unless container_name
+ raise ArgumentError.new('container_name is required')
+ end
+ request(
+ expects: 200,
+ headers: {},
+ idempotent: true,
+ method: :get,
+ path: container_name,
+ parser: Fog::Parsers::Storage::Azure::ListBlobs.new,
+ # parser: Fog::Parsers::Base.new,
+ query: {
+ 'restype' => 'container',
+ 'comp' => 'list'
+ }.merge!(options)
+ )
+ end
+
+ end
+ class Mock
+ end
+ end
+ end
+end
View
@@ -30,7 +30,7 @@ class Azure < Fog::Service
# request :set_container_acl
# request :lease_container
# request :delete_container
- # request :list_blobs
+ request :list_blobs
# request :put_blob
# request :get_blob
# request :get_blob_properties
@@ -51,6 +51,35 @@ class Azure < Fog::Service
module Utils
# put common functions between real and mock here
+
+
+ def extract_sub_dictionary(dict, *keys)
+ result = {}
+ for k, v in dict
+ if keys.include? k
+ result[k] = v
+ end
+ end
+ result
+ end
+
+ def stringify_keys(dict)
+ dict.inject({}) do |result, (key, value)|
+ result[key.to_s] = value
+ result
+ end
+ end
+
+ def extract_ms_metadata(dict)
+ result = {}
+ r = /^x-ms-meta-(?<name>.+)/
+ dict.keys.each do |key|
+ if key && (match = r.match(key))
+ result[match[:name]] = dict[key]
+ end
+ end
+ result
+ end
end
class Real
@@ -106,6 +135,7 @@ def setup_credentials(options)
end
def request(params, &block)
+ # TODO: Add retry logic.
#Setup headers
# params[:method] :get, :post, ...etc
# params[:query] = {:foo => 'bar'}
@@ -120,6 +150,8 @@ def request(params, &block)
headers["Authorization"] = "SharedKey #{@azure_storage_account_name}:#{get_signature(params)}"
begin
response = @connection.request(params, &block)
+ # rescue Excon::Errors::SocketError => e
+ # raise e.backtrace.inspect
rescue Excon::Errors::TemporaryRedirect => e
end
@@ -153,8 +185,8 @@ def canonicalize_headers(headers)
end
def canonicalize_resource(params)
result = ["/#{@azure_storage_account_name}/#{params[:path].sub('/', '')}",
- params[:query].keys.map {|k| "#{k.to_s.downcase.strip}:#{canonicalize_query_value(params[:query][k])}"}.join("\n")
- ].join("\n")
+ params[:query].keys.sort{ |a, b| a <=> b }.map {|k| "#{k.to_s.downcase.strip}:#{canonicalize_query_value(params[:query][k])}"}.join("\n")
+ ].join("\n").chomp
result
end
def canonicalize_query_value(value)

0 comments on commit 8f3a83c

Please sign in to comment.