citrusbyte-milton 0.3.2 → 0.3.3
Sign up to get free protection for your applications and to get access to all the features.
- data/lib/milton/core/tempfile.rb +6 -0
- data/lib/milton/derivatives/derivative.rb +1 -1
- data/lib/milton/derivatives/thumbnail.rb +14 -15
- data/lib/milton/storage/disk_file.rb +6 -0
- data/lib/milton/storage/s3_file.rb +14 -0
- data/lib/milton/storage/stored_file.rb +3 -4
- data/lib/milton.rb +17 -2
- data/test/milton/milton_test.rb +8 -0
- data/test/test_helper.rb +1 -1
- metadata +1 -1
data/lib/milton/core/tempfile.rb
CHANGED
@@ -33,6 +33,12 @@ module Milton
|
|
33
33
|
def path(tempfile_path, extension)
|
34
34
|
File.join(tempfile_path, filename(extension))
|
35
35
|
end
|
36
|
+
|
37
|
+
# Simple helper that returns a path to a tempfile with a uniquely
|
38
|
+
# generated basename and same extension as the given source.
|
39
|
+
def from(source)
|
40
|
+
filename(Milton::File.extension(source))
|
41
|
+
end
|
36
42
|
end
|
37
43
|
end
|
38
44
|
end
|
@@ -6,25 +6,21 @@ module Milton
|
|
6
6
|
def process
|
7
7
|
raise "target size must be specified for resizing" unless options.has_key?(:size)
|
8
8
|
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
# cases, so copy it to a tempfile first before processing
|
15
|
-
# source = Milton::Tempfile.create(self.source, @source.options[:tempfile_path]).path
|
16
|
-
|
9
|
+
temp_dst = File.join(settings[:tempfile_path], Milton::Tempfile.from(source.filename))
|
10
|
+
temp_src = File.join(settings[:tempfile_path], Milton::Tempfile.from(source.filename))
|
11
|
+
|
12
|
+
source.copy(temp_src)
|
13
|
+
|
17
14
|
if options[:crop]
|
18
15
|
crop = CropCalculator.new(image, Image.from_geometry(options[:size]))
|
19
16
|
size = crop.resizing_geometry
|
20
17
|
conversion_options = %Q(-gravity #{crop.gravity} -crop #{crop.cropping_geometry})
|
21
18
|
end
|
22
|
-
|
23
|
-
#
|
24
|
-
Milton.syscall(%Q{convert #{source} -geometry #{size || options[:size]} #{conversion_options || ''} +repage "#{destination}"})
|
19
|
+
|
20
|
+
Milton.syscall!(%Q{convert #{temp_src} -geometry #{size || options[:size]} #{conversion_options || ''} +repage "#{temp_dst}"})
|
25
21
|
|
26
22
|
# TODO: raise if the store fails
|
27
|
-
file.store(
|
23
|
+
file.store(temp_dst)
|
28
24
|
end
|
29
25
|
|
30
26
|
protected
|
@@ -33,10 +29,13 @@ module Milton
|
|
33
29
|
# 640-wide version of the image (so you're not generating tiny
|
34
30
|
# thumbnails from an 8-megapixel upload)
|
35
31
|
def source
|
36
|
-
image.width > 640 && Image.from_geometry(options[:size]).width < 640
|
37
|
-
Thumbnail.process(@source, { :size => '640x' }, settings).
|
32
|
+
@quick_source ||= if image.width > 640 && Image.from_geometry(options[:size]).width < 640
|
33
|
+
Thumbnail.process(@source, { :size => '640x' }, settings).file
|
34
|
+
else
|
35
|
+
@source
|
36
|
+
end
|
38
37
|
end
|
39
|
-
|
38
|
+
|
40
39
|
# Returns and memoizes an Image initialized from the file we're making a
|
41
40
|
# thumbnail of
|
42
41
|
def image
|
@@ -46,6 +46,12 @@ module Milton
|
|
46
46
|
FileUtils.rm_rf dirname if File.exists?(dirname)
|
47
47
|
end
|
48
48
|
|
49
|
+
# Copies this file to the given location on disk.
|
50
|
+
def copy(destination)
|
51
|
+
Milton.log "copying #{path} to #{destination}"
|
52
|
+
FileUtils.cp(path, destination)
|
53
|
+
end
|
54
|
+
|
49
55
|
# Returns the mime type of the file.
|
50
56
|
def mime_type
|
51
57
|
Milton.syscall("file -Ib #{path}").gsub(/\n/,"")
|
@@ -34,6 +34,20 @@ module Milton
|
|
34
34
|
bucket.key(key).try(:delete)
|
35
35
|
end
|
36
36
|
|
37
|
+
# Copies this file to the given location on disk.
|
38
|
+
# Note that this copies to a LOCAL location, not to another place on S3!
|
39
|
+
def copy(destination)
|
40
|
+
Milton.log "copying #{path} to #{destination}"
|
41
|
+
|
42
|
+
s3 = RightAws::S3Interface.new(options[:storage_options][:access_key_id], options[:storage_options][:secret_access_key], :logger => Rails.logger)
|
43
|
+
file = File.new(destination, 'wb')
|
44
|
+
|
45
|
+
# stream the download as opposed to downloading the whole thing and reading
|
46
|
+
# it all into memory at once since it might be gigantic...
|
47
|
+
s3.get(bucket_name, key) { |chunk| file.write(chunk) }
|
48
|
+
file.close
|
49
|
+
end
|
50
|
+
|
37
51
|
def mime_type
|
38
52
|
# TODO: implement
|
39
53
|
end
|
@@ -35,11 +35,10 @@ module Milton
|
|
35
35
|
self.options = options
|
36
36
|
end
|
37
37
|
|
38
|
-
# Creates a
|
38
|
+
# Creates a clone of this StoredFile of the same type with the same id
|
39
39
|
# and options but using the given filename. Doesn't actually do any
|
40
|
-
# copying of the underlying file data
|
41
|
-
|
42
|
-
def copy(filename)
|
40
|
+
# copying of the underlying file data.
|
41
|
+
def clone(filename)
|
43
42
|
self.class.new(filename, self.id, self.options)
|
44
43
|
end
|
45
44
|
end
|
data/lib/milton.rb
CHANGED
@@ -5,6 +5,7 @@ require 'milton/core/file'
|
|
5
5
|
module Milton
|
6
6
|
# Raised when a file which was expected to exist appears not to exist
|
7
7
|
class MissingFileError < StandardError;end;
|
8
|
+
class SyscallFailedError < RuntimeError;end;
|
8
9
|
|
9
10
|
# Some definitions for file semantics used throughout Milton, understanding
|
10
11
|
# this will make understanding the code a bit easier and avoid ambiguity:
|
@@ -72,11 +73,25 @@ module Milton
|
|
72
73
|
# Redirects stderr to log/milton.stderr.log in order to examine causes of
|
73
74
|
# failure.
|
74
75
|
def syscall(command)
|
76
|
+
begin
|
77
|
+
syscall!(command)
|
78
|
+
rescue Milton::SyscallFailedError => e
|
79
|
+
return false
|
80
|
+
end
|
81
|
+
end
|
82
|
+
module_function :syscall
|
83
|
+
|
84
|
+
def syscall!(command)
|
75
85
|
log("executing #{command}", invoker = Milton.called_by)
|
76
86
|
stdout = %x{#{command} 2>>#{File.join(Rails.root, 'log', 'milton.stderr.log')}}
|
77
|
-
$?.success?
|
87
|
+
unless $?.success?
|
88
|
+
e = Milton::SyscallFailedError.new(command)
|
89
|
+
log("failed to execute " + e.message, invoker)
|
90
|
+
raise e
|
91
|
+
end
|
92
|
+
stdout
|
78
93
|
end
|
79
|
-
module_function :syscall
|
94
|
+
module_function :syscall!
|
80
95
|
|
81
96
|
# Wraps +require+ on the given path in a rescue which uses the given
|
82
97
|
# message for the resulting LoadError on failure instead of the default
|
data/test/milton/milton_test.rb
CHANGED
@@ -10,4 +10,12 @@ class MiltonTest < ActiveSupport::TestCase
|
|
10
10
|
assert_equal "foo\n", Milton.syscall("echo foo")
|
11
11
|
end
|
12
12
|
end
|
13
|
+
|
14
|
+
context "running a syscall!" do
|
15
|
+
should "raise a Milton::SyscallFailedError if it fails" do
|
16
|
+
assert_raise Milton::SyscallFailedError do
|
17
|
+
Milton.syscall!('ls this_directory_definitely_doesnt_exist')
|
18
|
+
end
|
19
|
+
end
|
20
|
+
end
|
13
21
|
end
|
data/test/test_helper.rb
CHANGED
@@ -52,7 +52,7 @@ class Attachment < ActiveRecord::Base
|
|
52
52
|
end
|
53
53
|
|
54
54
|
class Image < ActiveRecord::Base
|
55
|
-
is_attachment :storage_options => { :root => ActiveSupport::TestCase.output_path }
|
55
|
+
is_attachment :storage_options => { :root => ActiveSupport::TestCase.output_path }
|
56
56
|
end
|
57
57
|
|
58
58
|
class Net::HTTP
|