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.
@@ -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