fog-dragonfly 0.8.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- data/.specopts +2 -0
- data/.yardopts +23 -0
- data/Gemfile +23 -0
- data/Gemfile.rails.2.3.5 +14 -0
- data/History.md +266 -0
- data/LICENSE +20 -0
- data/README.md +88 -0
- data/Rakefile +92 -0
- data/VERSION +1 -0
- data/config.ru +13 -0
- data/docs.watchr +1 -0
- data/dragonfly.gemspec +293 -0
- data/extra_docs/Analysers.md +108 -0
- data/extra_docs/Caching.md +23 -0
- data/extra_docs/Configuration.md +138 -0
- data/extra_docs/DataStorage.md +136 -0
- data/extra_docs/Encoding.md +96 -0
- data/extra_docs/GeneralUsage.md +121 -0
- data/extra_docs/Generators.md +102 -0
- data/extra_docs/Heroku.md +50 -0
- data/extra_docs/Index.md +36 -0
- data/extra_docs/MimeTypes.md +40 -0
- data/extra_docs/Models.md +266 -0
- data/extra_docs/Mongo.md +45 -0
- data/extra_docs/Processing.md +130 -0
- data/extra_docs/Rack.md +52 -0
- data/extra_docs/Rails2.md +55 -0
- data/extra_docs/Rails3.md +62 -0
- data/extra_docs/Sinatra.md +25 -0
- data/extra_docs/URLs.md +169 -0
- data/features/3.0.3.feature +8 -0
- data/features/images.feature +47 -0
- data/features/no_processing.feature +14 -0
- data/features/rails_2.3.5.feature +7 -0
- data/features/steps/common_steps.rb +8 -0
- data/features/steps/dragonfly_steps.rb +66 -0
- data/features/steps/rails_steps.rb +39 -0
- data/features/support/env.rb +40 -0
- data/fixtures/files/app/models/album.rb +3 -0
- data/fixtures/files/app/views/albums/new.html.erb +4 -0
- data/fixtures/files/app/views/albums/show.html.erb +4 -0
- data/fixtures/files/config/initializers/dragonfly.rb +4 -0
- data/fixtures/files/features/manage_album_images.feature +12 -0
- data/fixtures/files/features/step_definitions/image_steps.rb +15 -0
- data/fixtures/files/features/support/paths.rb +15 -0
- data/fixtures/files/features/text_images.feature +7 -0
- data/fixtures/rails_2.3.5/template.rb +10 -0
- data/fixtures/rails_3.0.3/template.rb +20 -0
- data/irbrc.rb +17 -0
- data/lib/dragonfly.rb +45 -0
- data/lib/dragonfly/active_model_extensions.rb +13 -0
- data/lib/dragonfly/active_model_extensions/attachment.rb +169 -0
- data/lib/dragonfly/active_model_extensions/class_methods.rb +45 -0
- data/lib/dragonfly/active_model_extensions/instance_methods.rb +28 -0
- data/lib/dragonfly/active_model_extensions/validations.rb +37 -0
- data/lib/dragonfly/analyser.rb +59 -0
- data/lib/dragonfly/analysis/file_command_analyser.rb +32 -0
- data/lib/dragonfly/analysis/image_magick_analyser.rb +47 -0
- data/lib/dragonfly/analysis/r_magick_analyser.rb +63 -0
- data/lib/dragonfly/app.rb +182 -0
- data/lib/dragonfly/config/heroku.rb +19 -0
- data/lib/dragonfly/config/image_magick.rb +41 -0
- data/lib/dragonfly/config/r_magick.rb +46 -0
- data/lib/dragonfly/config/rails.rb +17 -0
- data/lib/dragonfly/configurable.rb +119 -0
- data/lib/dragonfly/core_ext/object.rb +8 -0
- data/lib/dragonfly/core_ext/string.rb +9 -0
- data/lib/dragonfly/core_ext/symbol.rb +9 -0
- data/lib/dragonfly/data_storage.rb +9 -0
- data/lib/dragonfly/data_storage/file_data_store.rb +114 -0
- data/lib/dragonfly/data_storage/mongo_data_store.rb +82 -0
- data/lib/dragonfly/data_storage/s3data_store.rb +115 -0
- data/lib/dragonfly/encoder.rb +13 -0
- data/lib/dragonfly/encoding/image_magick_encoder.rb +57 -0
- data/lib/dragonfly/encoding/r_magick_encoder.rb +61 -0
- data/lib/dragonfly/function_manager.rb +69 -0
- data/lib/dragonfly/generation/hash_with_css_style_keys.rb +23 -0
- data/lib/dragonfly/generation/image_magick_generator.rb +140 -0
- data/lib/dragonfly/generation/r_magick_generator.rb +155 -0
- data/lib/dragonfly/generator.rb +9 -0
- data/lib/dragonfly/image_magick_utils.rb +81 -0
- data/lib/dragonfly/job.rb +371 -0
- data/lib/dragonfly/job_builder.rb +39 -0
- data/lib/dragonfly/job_definitions.rb +26 -0
- data/lib/dragonfly/job_endpoint.rb +15 -0
- data/lib/dragonfly/loggable.rb +28 -0
- data/lib/dragonfly/middleware.rb +34 -0
- data/lib/dragonfly/processing/image_magick_processor.rb +99 -0
- data/lib/dragonfly/processing/r_magick_processor.rb +126 -0
- data/lib/dragonfly/processor.rb +9 -0
- data/lib/dragonfly/r_magick_utils.rb +48 -0
- data/lib/dragonfly/rails/images.rb +22 -0
- data/lib/dragonfly/response.rb +82 -0
- data/lib/dragonfly/routed_endpoint.rb +40 -0
- data/lib/dragonfly/serializer.rb +32 -0
- data/lib/dragonfly/simple_cache.rb +23 -0
- data/lib/dragonfly/simple_endpoint.rb +63 -0
- data/lib/dragonfly/temp_object.rb +220 -0
- data/samples/beach.png +0 -0
- data/samples/egg.png +0 -0
- data/samples/round.gif +0 -0
- data/samples/sample.docx +0 -0
- data/samples/taj.jpg +0 -0
- data/spec/argument_matchers.rb +19 -0
- data/spec/dragonfly/active_model_extensions/active_model_setup.rb +97 -0
- data/spec/dragonfly/active_model_extensions/active_record_setup.rb +85 -0
- data/spec/dragonfly/active_model_extensions/model_spec.rb +723 -0
- data/spec/dragonfly/active_model_extensions/spec_helper.rb +11 -0
- data/spec/dragonfly/analyser_spec.rb +123 -0
- data/spec/dragonfly/analysis/file_command_analyser_spec.rb +57 -0
- data/spec/dragonfly/analysis/image_magick_analyser_spec.rb +15 -0
- data/spec/dragonfly/analysis/r_magick_analyser_spec.rb +27 -0
- data/spec/dragonfly/analysis/shared_analyser_spec.rb +51 -0
- data/spec/dragonfly/app_spec.rb +280 -0
- data/spec/dragonfly/config/r_magick_spec.rb +25 -0
- data/spec/dragonfly/configurable_spec.rb +220 -0
- data/spec/dragonfly/core_ext/string_spec.rb +17 -0
- data/spec/dragonfly/core_ext/symbol_spec.rb +17 -0
- data/spec/dragonfly/data_storage/data_store_spec.rb +76 -0
- data/spec/dragonfly/data_storage/file_data_store_spec.rb +169 -0
- data/spec/dragonfly/data_storage/mongo_data_store_spec.rb +38 -0
- data/spec/dragonfly/data_storage/s3_data_store_spec.rb +94 -0
- data/spec/dragonfly/deprecation_spec.rb +20 -0
- data/spec/dragonfly/encoding/image_magick_encoder_spec.rb +41 -0
- data/spec/dragonfly/encoding/r_magick_encoder_spec.rb +37 -0
- data/spec/dragonfly/function_manager_spec.rb +154 -0
- data/spec/dragonfly/generation/hash_with_css_style_keys_spec.rb +24 -0
- data/spec/dragonfly/generation/image_magick_generator_spec.rb +12 -0
- data/spec/dragonfly/generation/r_magick_generator_spec.rb +24 -0
- data/spec/dragonfly/generation/shared_generator_spec.rb +91 -0
- data/spec/dragonfly/image_magick_utils_spec.rb +16 -0
- data/spec/dragonfly/job_builder_spec.rb +37 -0
- data/spec/dragonfly/job_definitions_spec.rb +35 -0
- data/spec/dragonfly/job_endpoint_spec.rb +120 -0
- data/spec/dragonfly/job_spec.rb +773 -0
- data/spec/dragonfly/loggable_spec.rb +80 -0
- data/spec/dragonfly/middleware_spec.rb +68 -0
- data/spec/dragonfly/processing/image_magick_processor_spec.rb +29 -0
- data/spec/dragonfly/processing/r_magick_processor_spec.rb +26 -0
- data/spec/dragonfly/processing/shared_processing_spec.rb +215 -0
- data/spec/dragonfly/routed_endpoint_spec.rb +48 -0
- data/spec/dragonfly/serializer_spec.rb +61 -0
- data/spec/dragonfly/simple_cache_spec.rb +27 -0
- data/spec/dragonfly/simple_endpoint_spec.rb +89 -0
- data/spec/dragonfly/temp_object_spec.rb +352 -0
- data/spec/image_matchers.rb +47 -0
- data/spec/simple_matchers.rb +44 -0
- data/spec/spec_helper.rb +58 -0
- data/yard/handlers/configurable_attr_handler.rb +38 -0
- data/yard/setup.rb +15 -0
- data/yard/templates/default/fulldoc/html/css/common.css +107 -0
- data/yard/templates/default/layout/html/layout.erb +87 -0
- data/yard/templates/default/module/html/configuration_summary.erb +31 -0
- data/yard/templates/default/module/setup.rb +17 -0
- metadata +550 -0
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
module Dragonfly
|
|
2
|
+
module Config
|
|
3
|
+
|
|
4
|
+
module Heroku
|
|
5
|
+
|
|
6
|
+
def self.apply_configuration(app, bucket_name)
|
|
7
|
+
app.configure do |c|
|
|
8
|
+
c.datastore = Dragonfly::DataStorage::S3DataStore.new
|
|
9
|
+
c.datastore.configure do |d|
|
|
10
|
+
d.bucket_name = bucket_name
|
|
11
|
+
d.access_key_id = ENV['S3_KEY'] || raise("ENV variable 'S3_KEY' needs to be set - use\n\theroku config:add S3_KEY=XXXXXXXXX")
|
|
12
|
+
d.secret_access_key = ENV['S3_SECRET'] || raise("ENV variable 'S3_SECRET' needs to be set - use\n\theroku config:add S3_SECRET=XXXXXXXXX")
|
|
13
|
+
end
|
|
14
|
+
end
|
|
15
|
+
end
|
|
16
|
+
|
|
17
|
+
end
|
|
18
|
+
end
|
|
19
|
+
end
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
module Dragonfly
|
|
2
|
+
module Config
|
|
3
|
+
|
|
4
|
+
# ImageMagick is a saved configuration for Dragonfly apps, which does the following:
|
|
5
|
+
# - registers an imagemagick analyser
|
|
6
|
+
# - registers an imagemagick processor
|
|
7
|
+
# - registers an imagemagick encoder
|
|
8
|
+
# - adds thumb shortcuts like '280x140!', etc.
|
|
9
|
+
# Look at the source code for apply_configuration to see exactly how it configures the app.
|
|
10
|
+
module ImageMagick
|
|
11
|
+
|
|
12
|
+
def self.apply_configuration(app, opts={})
|
|
13
|
+
app.configure do |c|
|
|
14
|
+
c.analyser.register(Analysis::ImageMagickAnalyser)
|
|
15
|
+
c.processor.register(Processing::ImageMagickProcessor)
|
|
16
|
+
c.encoder.register(Encoding::ImageMagickEncoder)
|
|
17
|
+
c.generator.register(Generation::ImageMagickGenerator)
|
|
18
|
+
|
|
19
|
+
c.job :thumb do |geometry, format|
|
|
20
|
+
process :thumb, geometry
|
|
21
|
+
encode format if format
|
|
22
|
+
end
|
|
23
|
+
c.job :gif do
|
|
24
|
+
encode :gif
|
|
25
|
+
end
|
|
26
|
+
c.job :jpg do
|
|
27
|
+
encode :jpg
|
|
28
|
+
end
|
|
29
|
+
c.job :png do
|
|
30
|
+
encode :png
|
|
31
|
+
end
|
|
32
|
+
c.job :convert do |args, format|
|
|
33
|
+
process :convert, args, format
|
|
34
|
+
end
|
|
35
|
+
end
|
|
36
|
+
|
|
37
|
+
end
|
|
38
|
+
|
|
39
|
+
end
|
|
40
|
+
end
|
|
41
|
+
end
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
module Dragonfly
|
|
2
|
+
module Config
|
|
3
|
+
|
|
4
|
+
# RMagick is a saved configuration for Dragonfly apps, which does the following:
|
|
5
|
+
# - registers an rmagick analyser
|
|
6
|
+
# - registers an rmagick processor
|
|
7
|
+
# - registers an rmagick encoder
|
|
8
|
+
# - adds thumb shortcuts like '280x140!', etc.
|
|
9
|
+
# Look at the source code for apply_configuration to see exactly how it configures the app.
|
|
10
|
+
module RMagick
|
|
11
|
+
|
|
12
|
+
def self.apply_configuration(app, opts={})
|
|
13
|
+
use_filesystem = opts.has_key?(:use_filesystem) ? opts[:use_filesystem] : true
|
|
14
|
+
app.configure do |c|
|
|
15
|
+
c.analyser.register(Analysis::RMagickAnalyser) do |a|
|
|
16
|
+
a.use_filesystem = use_filesystem
|
|
17
|
+
end
|
|
18
|
+
c.processor.register(Processing::RMagickProcessor) do |p|
|
|
19
|
+
p.use_filesystem = use_filesystem
|
|
20
|
+
end
|
|
21
|
+
c.encoder.register(Encoding::RMagickEncoder) do |e|
|
|
22
|
+
e.use_filesystem = use_filesystem
|
|
23
|
+
end
|
|
24
|
+
c.generator.register(Generation::RMagickGenerator) do |g|
|
|
25
|
+
g.use_filesystem = use_filesystem
|
|
26
|
+
end
|
|
27
|
+
c.job :thumb do |geometry, format|
|
|
28
|
+
process :thumb, geometry
|
|
29
|
+
encode format if format
|
|
30
|
+
end
|
|
31
|
+
c.job :gif do
|
|
32
|
+
encode :gif
|
|
33
|
+
end
|
|
34
|
+
c.job :jpg do
|
|
35
|
+
encode :jpg
|
|
36
|
+
end
|
|
37
|
+
c.job :png do
|
|
38
|
+
encode :png
|
|
39
|
+
end
|
|
40
|
+
end
|
|
41
|
+
|
|
42
|
+
end
|
|
43
|
+
|
|
44
|
+
end
|
|
45
|
+
end
|
|
46
|
+
end
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
module Dragonfly
|
|
2
|
+
module Config
|
|
3
|
+
|
|
4
|
+
module Rails
|
|
5
|
+
|
|
6
|
+
def self.apply_configuration(app)
|
|
7
|
+
app.configure do |c|
|
|
8
|
+
c.log = ::Rails.logger
|
|
9
|
+
c.datastore.root_path = "#{::Rails.root}/public/system/dragonfly/#{::Rails.env}" if c.datastore.is_a?(DataStorage::FileDataStore)
|
|
10
|
+
c.url_path_prefix = '/media'
|
|
11
|
+
c.analyser.register(Analysis::FileCommandAnalyser)
|
|
12
|
+
end
|
|
13
|
+
end
|
|
14
|
+
|
|
15
|
+
end
|
|
16
|
+
end
|
|
17
|
+
end
|
|
@@ -0,0 +1,119 @@
|
|
|
1
|
+
module Dragonfly
|
|
2
|
+
module Configurable
|
|
3
|
+
|
|
4
|
+
# Exceptions
|
|
5
|
+
class BadConfigAttribute < StandardError; end
|
|
6
|
+
|
|
7
|
+
def self.included(klass)
|
|
8
|
+
klass.class_eval do
|
|
9
|
+
include Configurable::InstanceMethods
|
|
10
|
+
extend Configurable::ClassMethods
|
|
11
|
+
|
|
12
|
+
# These aren't included in InstanceMethods because we need access to 'klass'
|
|
13
|
+
# We can't just put them into InstanceMethods and use 'self.class' because
|
|
14
|
+
# this won't always point to the class in which we've included Configurable,
|
|
15
|
+
# e.g. if we've included it in an eigenclasse
|
|
16
|
+
define_method :configuration_hash do
|
|
17
|
+
@configuration_hash ||= klass.default_configuration.dup
|
|
18
|
+
end
|
|
19
|
+
private :configuration_hash
|
|
20
|
+
|
|
21
|
+
define_method :configuration_methods do
|
|
22
|
+
klass.configuration_methods
|
|
23
|
+
end
|
|
24
|
+
|
|
25
|
+
end
|
|
26
|
+
end
|
|
27
|
+
|
|
28
|
+
class DeferredBlock < Proc; end
|
|
29
|
+
|
|
30
|
+
module InstanceMethods
|
|
31
|
+
|
|
32
|
+
def configure(&block)
|
|
33
|
+
yield ConfigurationProxy.new(self)
|
|
34
|
+
self
|
|
35
|
+
end
|
|
36
|
+
|
|
37
|
+
def configure_with(configurer, *args, &block)
|
|
38
|
+
configurer = configurer_for(configurer) if configurer.is_a?(Symbol)
|
|
39
|
+
configurer.apply_configuration(self, *args)
|
|
40
|
+
configure(&block) if block
|
|
41
|
+
self
|
|
42
|
+
end
|
|
43
|
+
|
|
44
|
+
def configuration
|
|
45
|
+
configuration_hash.dup
|
|
46
|
+
end
|
|
47
|
+
|
|
48
|
+
def has_configuration_method?(method_name)
|
|
49
|
+
configuration_methods.include?(method_name.to_sym)
|
|
50
|
+
end
|
|
51
|
+
|
|
52
|
+
end
|
|
53
|
+
|
|
54
|
+
module ClassMethods
|
|
55
|
+
|
|
56
|
+
def default_configuration
|
|
57
|
+
@default_configuration ||= {}
|
|
58
|
+
end
|
|
59
|
+
|
|
60
|
+
def configuration_methods
|
|
61
|
+
@configuration_methods ||= []
|
|
62
|
+
end
|
|
63
|
+
|
|
64
|
+
private
|
|
65
|
+
|
|
66
|
+
def configurable_attr attribute, default=nil, &blk
|
|
67
|
+
default_configuration[attribute] = blk ? DeferredBlock.new(&blk) : default
|
|
68
|
+
|
|
69
|
+
# Define the reader
|
|
70
|
+
define_method(attribute) do
|
|
71
|
+
if configuration_hash[attribute].is_a?(DeferredBlock)
|
|
72
|
+
configuration_hash[attribute] = configuration_hash[attribute].call
|
|
73
|
+
end
|
|
74
|
+
configuration_hash[attribute]
|
|
75
|
+
end
|
|
76
|
+
|
|
77
|
+
# Define the writer
|
|
78
|
+
define_method("#{attribute}=") do |value|
|
|
79
|
+
configuration_hash[attribute] = value
|
|
80
|
+
end
|
|
81
|
+
|
|
82
|
+
configuration_method attribute
|
|
83
|
+
configuration_method "#{attribute}="
|
|
84
|
+
end
|
|
85
|
+
|
|
86
|
+
def configuration_method(*method_names)
|
|
87
|
+
configuration_methods.push(*method_names.map{|n| n.to_sym })
|
|
88
|
+
end
|
|
89
|
+
|
|
90
|
+
end
|
|
91
|
+
|
|
92
|
+
class ConfigurationProxy
|
|
93
|
+
|
|
94
|
+
def initialize(owner)
|
|
95
|
+
@owner = owner
|
|
96
|
+
end
|
|
97
|
+
|
|
98
|
+
def method_missing(method_name, *args, &block)
|
|
99
|
+
if owner.has_configuration_method?(method_name)
|
|
100
|
+
owner.send(method_name, *args, &block)
|
|
101
|
+
elsif nested_configurable?(method_name, *args)
|
|
102
|
+
owner.send(method_name, *args)
|
|
103
|
+
else
|
|
104
|
+
raise BadConfigAttribute, "You tried to configure using '#{method_name.inspect}', but the valid config attributes are #{owner.configuration_methods.map{|a| %('#{a.inspect}') }.sort.join(', ')}"
|
|
105
|
+
end
|
|
106
|
+
end
|
|
107
|
+
|
|
108
|
+
private
|
|
109
|
+
|
|
110
|
+
attr_reader :owner
|
|
111
|
+
|
|
112
|
+
def nested_configurable?(method, *args)
|
|
113
|
+
owner.respond_to?(method) && owner.send(method, *args).is_a?(Configurable)
|
|
114
|
+
end
|
|
115
|
+
|
|
116
|
+
end
|
|
117
|
+
|
|
118
|
+
end
|
|
119
|
+
end
|
|
@@ -0,0 +1,114 @@
|
|
|
1
|
+
require 'pathname'
|
|
2
|
+
|
|
3
|
+
module Dragonfly
|
|
4
|
+
module DataStorage
|
|
5
|
+
|
|
6
|
+
class FileDataStore
|
|
7
|
+
|
|
8
|
+
include Configurable
|
|
9
|
+
|
|
10
|
+
configurable_attr :root_path, '/var/tmp/dragonfly'
|
|
11
|
+
|
|
12
|
+
def store(temp_object, opts={})
|
|
13
|
+
relative_path = if opts[:path]
|
|
14
|
+
opts[:path]
|
|
15
|
+
else
|
|
16
|
+
filename = temp_object.name || 'file'
|
|
17
|
+
relative_path = relative_path_for(filename)
|
|
18
|
+
end
|
|
19
|
+
|
|
20
|
+
begin
|
|
21
|
+
path = absolute(relative_path)
|
|
22
|
+
until !File.exist?(path)
|
|
23
|
+
path = disambiguate(path)
|
|
24
|
+
end
|
|
25
|
+
prepare_path(path)
|
|
26
|
+
temp_object.to_file(path).close
|
|
27
|
+
store_extra_data(path, temp_object)
|
|
28
|
+
rescue Errno::EACCES => e
|
|
29
|
+
raise UnableToStore, e.message
|
|
30
|
+
end
|
|
31
|
+
|
|
32
|
+
relative(path)
|
|
33
|
+
end
|
|
34
|
+
|
|
35
|
+
def retrieve(relative_path)
|
|
36
|
+
path = absolute(relative_path)
|
|
37
|
+
file = File.new(path)
|
|
38
|
+
file.close
|
|
39
|
+
[
|
|
40
|
+
file,
|
|
41
|
+
retrieve_extra_data(path)
|
|
42
|
+
]
|
|
43
|
+
rescue Errno::ENOENT => e
|
|
44
|
+
raise DataNotFound, e.message
|
|
45
|
+
end
|
|
46
|
+
|
|
47
|
+
def destroy(relative_path)
|
|
48
|
+
path = absolute(relative_path)
|
|
49
|
+
FileUtils.rm path
|
|
50
|
+
FileUtils.rm extra_data_path(path)
|
|
51
|
+
purge_empty_directories(relative_path)
|
|
52
|
+
rescue Errno::ENOENT => e
|
|
53
|
+
raise DataNotFound, e.message
|
|
54
|
+
end
|
|
55
|
+
|
|
56
|
+
def disambiguate(path)
|
|
57
|
+
dirname = File.dirname(path)
|
|
58
|
+
basename = File.basename(path, '.*')
|
|
59
|
+
extname = File.extname(path)
|
|
60
|
+
"#{dirname}/#{basename}_#{Time.now.usec.to_s(32)}#{extname}"
|
|
61
|
+
end
|
|
62
|
+
|
|
63
|
+
private
|
|
64
|
+
|
|
65
|
+
def absolute(relative_path)
|
|
66
|
+
File.join(root_path, relative_path)
|
|
67
|
+
end
|
|
68
|
+
|
|
69
|
+
def relative(absolute_path)
|
|
70
|
+
absolute_path[/^#{root_path}\/?(.*)$/, 1]
|
|
71
|
+
end
|
|
72
|
+
|
|
73
|
+
def directory_empty?(path)
|
|
74
|
+
Dir.entries(path) == ['.','..']
|
|
75
|
+
end
|
|
76
|
+
|
|
77
|
+
def extra_data_path(data_path)
|
|
78
|
+
"#{data_path}.extra"
|
|
79
|
+
end
|
|
80
|
+
|
|
81
|
+
def relative_path_for(filename)
|
|
82
|
+
time = Time.now
|
|
83
|
+
msec = time.usec / 1000
|
|
84
|
+
"#{time.strftime '%Y/%m/%d/%H_%M_%S'}_#{msec}_#{filename.gsub(/[^\w.]+/,'_')}"
|
|
85
|
+
end
|
|
86
|
+
|
|
87
|
+
def store_extra_data(data_path, temp_object)
|
|
88
|
+
File.open(extra_data_path(data_path), 'wb') do |f|
|
|
89
|
+
f.write Marshal.dump(temp_object.attributes)
|
|
90
|
+
end
|
|
91
|
+
end
|
|
92
|
+
|
|
93
|
+
def retrieve_extra_data(data_path)
|
|
94
|
+
path = extra_data_path(data_path)
|
|
95
|
+
File.exist?(path) ? File.open(path,'rb'){|f| Marshal.load(f.read) } : {}
|
|
96
|
+
end
|
|
97
|
+
|
|
98
|
+
def prepare_path(path)
|
|
99
|
+
dir = File.dirname(path)
|
|
100
|
+
FileUtils.mkdir_p(dir) unless File.exist?(dir)
|
|
101
|
+
end
|
|
102
|
+
|
|
103
|
+
def purge_empty_directories(path)
|
|
104
|
+
containing_directory = Pathname.new(path).dirname
|
|
105
|
+
containing_directory.ascend do |relative_dir|
|
|
106
|
+
dir = absolute(relative_dir)
|
|
107
|
+
FileUtils.rmdir dir if directory_empty?(dir)
|
|
108
|
+
end
|
|
109
|
+
end
|
|
110
|
+
|
|
111
|
+
end
|
|
112
|
+
|
|
113
|
+
end
|
|
114
|
+
end
|
|
@@ -0,0 +1,82 @@
|
|
|
1
|
+
require 'mongo'
|
|
2
|
+
|
|
3
|
+
module Dragonfly
|
|
4
|
+
module DataStorage
|
|
5
|
+
class MongoDataStore
|
|
6
|
+
|
|
7
|
+
include Configurable
|
|
8
|
+
include Serializer
|
|
9
|
+
|
|
10
|
+
configurable_attr :host
|
|
11
|
+
configurable_attr :port
|
|
12
|
+
configurable_attr :database, 'dragonfly'
|
|
13
|
+
configurable_attr :username
|
|
14
|
+
configurable_attr :password
|
|
15
|
+
|
|
16
|
+
# Mongo gem deprecated ObjectID in favour of ObjectId
|
|
17
|
+
OBJECT_ID = defined?(BSON::ObjectId) ? BSON::ObjectId : BSON::ObjectID
|
|
18
|
+
INVALID_OBJECT_ID = defined?(BSON::InvalidObjectId) ? BSON::InvalidObjectId : BSON::InvalidObjectID
|
|
19
|
+
|
|
20
|
+
def initialize(opts={})
|
|
21
|
+
self.host = opts[:host]
|
|
22
|
+
self.port = opts[:port]
|
|
23
|
+
self.database = opts[:database] if opts[:database]
|
|
24
|
+
self.username = opts[:username]
|
|
25
|
+
self.password = opts[:password]
|
|
26
|
+
end
|
|
27
|
+
|
|
28
|
+
def store(temp_object, opts={})
|
|
29
|
+
ensure_authenticated!
|
|
30
|
+
temp_object.file do |f|
|
|
31
|
+
mongo_id = grid.put(f, :metadata => marshal_encode(temp_object.attributes))
|
|
32
|
+
mongo_id.to_s
|
|
33
|
+
end
|
|
34
|
+
end
|
|
35
|
+
|
|
36
|
+
def retrieve(uid)
|
|
37
|
+
ensure_authenticated!
|
|
38
|
+
grid_io = grid.get(bson_id(uid))
|
|
39
|
+
extra = marshal_decode(grid_io.metadata)
|
|
40
|
+
extra[:meta].merge!(:stored_at => grid_io.upload_date)
|
|
41
|
+
[
|
|
42
|
+
grid_io.read,
|
|
43
|
+
extra
|
|
44
|
+
]
|
|
45
|
+
rescue Mongo::GridFileNotFound, INVALID_OBJECT_ID => e
|
|
46
|
+
raise DataNotFound, "#{e} - #{uid}"
|
|
47
|
+
end
|
|
48
|
+
|
|
49
|
+
def destroy(uid)
|
|
50
|
+
ensure_authenticated!
|
|
51
|
+
grid.delete(bson_id(uid))
|
|
52
|
+
rescue Mongo::GridFileNotFound, INVALID_OBJECT_ID => e
|
|
53
|
+
raise DataNotFound, "#{e} - #{uid}"
|
|
54
|
+
end
|
|
55
|
+
|
|
56
|
+
def connection
|
|
57
|
+
@connection ||= Mongo::Connection.new(host, port)
|
|
58
|
+
end
|
|
59
|
+
|
|
60
|
+
def db
|
|
61
|
+
@db ||= connection.db(database)
|
|
62
|
+
end
|
|
63
|
+
|
|
64
|
+
def grid
|
|
65
|
+
@grid ||= Mongo::Grid.new(db)
|
|
66
|
+
end
|
|
67
|
+
|
|
68
|
+
private
|
|
69
|
+
|
|
70
|
+
def ensure_authenticated!
|
|
71
|
+
if username
|
|
72
|
+
@authenticated ||= db.authenticate(username, password)
|
|
73
|
+
end
|
|
74
|
+
end
|
|
75
|
+
|
|
76
|
+
def bson_id(uid)
|
|
77
|
+
OBJECT_ID.from_string(uid)
|
|
78
|
+
end
|
|
79
|
+
|
|
80
|
+
end
|
|
81
|
+
end
|
|
82
|
+
end
|