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.
@@ -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
@@ -100,7 +100,7 @@ module Milton
100
100
  # Returns the StoredFile which represents the Derivative (which is a copy
101
101
  # of the source w/ a different filename).
102
102
  def file
103
- @file ||= @source.copy(filename)
103
+ @file ||= @source.clone(filename)
104
104
  end
105
105
  end
106
106
  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
- destination = Milton::Tempfile.path(settings[:tempfile_path], Milton::File.extension(@source.filename))
10
-
11
- # TODO: determine if this is neccessary or was just a problem w/ the
12
- # way we were calling convert
13
- # convert can be destructive to the original image in certain failure
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
- # TODO: raise if the syscall fails
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(destination)
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).path : @source.path
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 "copy" of this StoredFile of the same type with the same id
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, just creates a "copy" of the
41
- # StoredFile object.
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? ? stdout : (log("failed to execute #{command}", invoker) and return false)
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
@@ -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 }, :processors => { :thumbnail => { :postprocessing => true } }
55
+ is_attachment :storage_options => { :root => ActiveSupport::TestCase.output_path }
56
56
  end
57
57
 
58
58
  class Net::HTTP
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: citrusbyte-milton
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.3.2
4
+ version: 0.3.3
5
5
  platform: ruby
6
6
  authors:
7
7
  - Ben Alavi