citrusbyte-milton 0.3.2 → 0.3.3
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/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
|