image_optim 0.13.3 → 0.14.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +8 -8
- data/.rubocop.yml +56 -0
- data/.travis.yml +3 -1
- data/README.markdown +23 -10
- data/bin/image_optim +25 -15
- data/image_optim.gemspec +5 -2
- data/lib/image_optim.rb +47 -37
- data/lib/image_optim/bin_resolver.rb +17 -12
- data/lib/image_optim/bin_resolver/comparable_condition.rb +23 -7
- data/lib/image_optim/bin_resolver/simple_version.rb +2 -0
- data/lib/image_optim/config.rb +21 -13
- data/lib/image_optim/handler.rb +18 -12
- data/lib/image_optim/hash_helpers.rb +23 -13
- data/lib/image_optim/image_meta.rb +1 -0
- data/lib/image_optim/image_path.rb +14 -13
- data/lib/image_optim/option_definition.rb +11 -9
- data/lib/image_optim/option_helpers.rb +1 -2
- data/lib/image_optim/railtie.rb +18 -15
- data/lib/image_optim/runner.rb +67 -61
- data/lib/image_optim/space.rb +29 -0
- data/lib/image_optim/true_false_nil.rb +9 -1
- data/lib/image_optim/worker.rb +40 -16
- data/lib/image_optim/worker/advpng.rb +8 -1
- data/lib/image_optim/worker/gifsicle.rb +13 -1
- data/lib/image_optim/worker/jhead.rb +5 -0
- data/lib/image_optim/worker/jpegoptim.rb +17 -4
- data/lib/image_optim/worker/jpegtran.rb +9 -1
- data/lib/image_optim/worker/optipng.rb +13 -2
- data/lib/image_optim/worker/pngcrush.rb +14 -5
- data/lib/image_optim/worker/pngout.rb +10 -2
- data/lib/image_optim/worker/svgo.rb +1 -0
- data/script/update_worker_options_in_readme +42 -27
- data/spec/image_optim/bin_resolver/comparable_condition_spec.rb +13 -13
- data/spec/image_optim/bin_resolver/simple_version_spec.rb +4 -4
- data/spec/image_optim/bin_resolver_spec.rb +65 -37
- data/spec/image_optim/config_spec.rb +121 -110
- data/spec/image_optim/handler_spec.rb +29 -18
- data/spec/image_optim/hash_helpers_spec.rb +29 -27
- data/spec/image_optim/image_path_spec.rb +17 -17
- data/spec/image_optim/space_spec.rb +24 -0
- data/spec/image_optim/worker_spec.rb +18 -0
- data/spec/image_optim_spec.rb +134 -74
- metadata +27 -7
- data/script/update_instructions_in_readme +0 -44
checksums.yaml
CHANGED
@@ -1,15 +1,15 @@
|
|
1
1
|
---
|
2
2
|
!binary "U0hBMQ==":
|
3
3
|
metadata.gz: !binary |-
|
4
|
-
|
4
|
+
MDYzNDg2MTY5NjdlNGIyY2U3NzY0Mzc5MTc1YzA3N2I3MGRmNDQ0Yw==
|
5
5
|
data.tar.gz: !binary |-
|
6
|
-
|
6
|
+
OTcyM2IxMWJjOTA4NDYyYTVkMjcwNTI4MDI5NzE0OTVmYjI5MzE0NQ==
|
7
7
|
!binary "U0hBNTEy":
|
8
8
|
metadata.gz: !binary |-
|
9
|
-
|
10
|
-
|
11
|
-
|
9
|
+
N2ViYzljYTU3OGVkMzQ5OTNmNmYyM2RmZjdmZDZmN2E4MDA0MmJmNGI5MjFk
|
10
|
+
Yzc1NDFjYWM0NjgxZTU0ZWQwMjc0MmVjNGM1MjEyYmQ3MzhmNTlmYWNkZjU3
|
11
|
+
Mzc1Mjc2Y2M0NWNkZGM3OTFlN2ZjZDNiM2EwOGRmNjY0MmIxM2M=
|
12
12
|
data.tar.gz: !binary |-
|
13
|
-
|
14
|
-
|
15
|
-
|
13
|
+
Y2M4Y2I4ZTNiYjZhYThmYThhNTQxYjQ4N2UxZDhhNmU4NjQ1MmI2NmY1YTdh
|
14
|
+
MGI3YTI1YjRiZmIyYmQ5NGE4MDI2NmVjNGY1YWNmNmRkMDM3MzZhMGY3ZjQ5
|
15
|
+
MjYwZmJhOWNkYTM3YWU3NTc4OTQwMThiZjhmY2RkY2Y5ZTc3ZmY=
|
data/.rubocop.yml
ADDED
@@ -0,0 +1,56 @@
|
|
1
|
+
AllCops:
|
2
|
+
Exclude:
|
3
|
+
- '*.gemspec'
|
4
|
+
|
5
|
+
Lint/EndAlignment:
|
6
|
+
AlignWith: variable
|
7
|
+
|
8
|
+
Style/AccessModifierIndentation:
|
9
|
+
EnforcedStyle: outdent
|
10
|
+
|
11
|
+
Style/CaseIndentation:
|
12
|
+
IndentWhenRelativeTo: end
|
13
|
+
|
14
|
+
Style/ClassLength:
|
15
|
+
Max: 120
|
16
|
+
|
17
|
+
Style/CyclomaticComplexity:
|
18
|
+
Max: 8
|
19
|
+
|
20
|
+
Style/DotPosition:
|
21
|
+
EnforcedStyle: trailing
|
22
|
+
|
23
|
+
Style/DoubleNegation:
|
24
|
+
Enabled: false
|
25
|
+
|
26
|
+
Style/Encoding:
|
27
|
+
EnforcedStyle: when_needed
|
28
|
+
|
29
|
+
Style/HashSyntax:
|
30
|
+
EnforcedStyle: hash_rockets
|
31
|
+
|
32
|
+
Style/IfUnlessModifier:
|
33
|
+
MaxLineLength: 40
|
34
|
+
|
35
|
+
Style/IndentHash:
|
36
|
+
EnforcedStyle: consistent
|
37
|
+
|
38
|
+
Style/MethodLength:
|
39
|
+
Max: 20
|
40
|
+
|
41
|
+
Style/PercentLiteralDelimiters:
|
42
|
+
PreferredDelimiters:
|
43
|
+
'%w': '[]'
|
44
|
+
'%W': '[]'
|
45
|
+
|
46
|
+
Style/Semicolon:
|
47
|
+
AllowAsExpressionSeparator: true
|
48
|
+
|
49
|
+
Style/SpaceBeforeBlockBraces:
|
50
|
+
EnforcedStyle: no_space
|
51
|
+
|
52
|
+
Style/SpaceInsideHashLiteralBraces:
|
53
|
+
EnforcedStyle: no_space
|
54
|
+
|
55
|
+
Style/TrailingComma:
|
56
|
+
EnforcedStyleForMultiline: comma
|
data/.travis.yml
CHANGED
@@ -11,7 +11,9 @@ rvm:
|
|
11
11
|
- jruby-19mode
|
12
12
|
- jruby-head
|
13
13
|
- ree
|
14
|
-
script:
|
14
|
+
script:
|
15
|
+
- bundle exec rspec
|
16
|
+
- '! bundle show rubocop || bundle exec rubocop' # run rubocop only if it is bundled
|
15
17
|
before_install:
|
16
18
|
- sudo apt-get update -qq
|
17
19
|
- sudo apt-get install -qq advancecomp gifsicle jhead jpegoptim libjpeg-progs optipng pngcrush
|
data/README.markdown
CHANGED
@@ -1,3 +1,10 @@
|
|
1
|
+
[![Gem Version](https://img.shields.io/gem/v/image_optim.svg)](https://rubygems.org/gems/image_optim)
|
2
|
+
[![Build Status](https://img.shields.io/travis/toy/image_optim/master.svg)](https://travis-ci.org/toy/image_optim)
|
3
|
+
[![Code Climate](https://img.shields.io/codeclimate/github/toy/image_optim.svg)](https://codeclimate.com/github/toy/image_optim)
|
4
|
+
[![Dependency Status](https://img.shields.io/gemnasium/toy/image_optim.svg)](https://gemnasium.com/toy/image_optim)
|
5
|
+
[![Inch CI](http://inch-ci.org/github/toy/image_optim.svg?branch=master)](http://inch-ci.org/github/toy/image_optim)
|
6
|
+
[![Gittip](https://img.shields.io/gittip/toy.svg)](https://www.gittip.com/toy/)
|
7
|
+
|
1
8
|
# image_optim
|
2
9
|
|
3
10
|
Optimize (lossless compress) images (jpeg, png, gif, svg) using external utilities:
|
@@ -15,10 +22,7 @@ Optimize (lossless compress) images (jpeg, png, gif, svg) using external utiliti
|
|
15
22
|
|
16
23
|
Based on [ImageOptim.app](http://imageoptim.com/).
|
17
24
|
|
18
|
-
[
|
19
|
-
[![Build Status](https://travis-ci.org/toy/image_optim.png?branch=master)](https://travis-ci.org/toy/image_optim)
|
20
|
-
[![Code Climate](https://codeclimate.com/github/toy/image_optim.png)](https://codeclimate.com/github/toy/image_optim)
|
21
|
-
[![Dependency Status](https://gemnasium.com/toy/image_optim.png)](https://gemnasium.com/toy/image_optim)
|
25
|
+
Documentation for [latest version](http://rubydoc.info/gems/image_optim/frames) and [master](http://rubydoc.info/github/toy/image_optim/master/frames).
|
22
26
|
|
23
27
|
## Gem installation
|
24
28
|
|
@@ -29,16 +33,19 @@ gem install image_optim
|
|
29
33
|
### Bundler
|
30
34
|
|
31
35
|
Add to your `Gemfile`:
|
36
|
+
|
32
37
|
```ruby
|
33
38
|
gem 'image_optim'
|
34
39
|
```
|
35
40
|
|
36
41
|
With version:
|
42
|
+
|
37
43
|
```ruby
|
38
44
|
gem 'image_optim', '~> 0.11'
|
39
45
|
```
|
40
46
|
|
41
47
|
If you want to check latest changes:
|
48
|
+
|
42
49
|
```ruby
|
43
50
|
gem 'image_optim', :git => 'git://github.com/toy/image_optim.git'
|
44
51
|
```
|
@@ -93,21 +100,27 @@ You will also need to install `jpegoptim` and `pngcrush` from source:
|
|
93
100
|
|
94
101
|
#### jpegoptim
|
95
102
|
|
103
|
+
Replace `X.Y.Z` with latest version number from http://www.kokkonen.net/tjko/projects.html#jpegoptim.
|
104
|
+
|
96
105
|
```bash
|
106
|
+
JPEGOPTIM_VERSION=X.Y.Z
|
97
107
|
cd /tmp
|
98
|
-
curl -O http://www.kokkonen.net/tjko/src/jpegoptim
|
99
|
-
tar zxf jpegoptim
|
100
|
-
cd jpegoptim
|
108
|
+
curl -O http://www.kokkonen.net/tjko/src/jpegoptim-$JPEGOPTIM_VERSION.tar.gz
|
109
|
+
tar zxf jpegoptim-$JPEGOPTIM_VERSION.tar.gz
|
110
|
+
cd jpegoptim-$JPEGOPTIM_VERSION
|
101
111
|
./configure && make && make install
|
102
112
|
```
|
103
113
|
|
104
114
|
#### pngcrush
|
105
115
|
|
116
|
+
Replace `X.Y.Z` with latest version number from http://sourceforge.net/projects/pmt/files/pngcrush/.
|
117
|
+
|
106
118
|
```bash
|
119
|
+
PNGCRUSH_VERSION=X.Y.Z
|
107
120
|
cd /tmp
|
108
|
-
curl -O http://iweb.dl.sourceforge.net/project/pmt/pngcrush/
|
109
|
-
tar zxf pngcrush
|
110
|
-
cd pngcrush
|
121
|
+
curl -O http://iweb.dl.sourceforge.net/project/pmt/pngcrush/$PNGCRUSH_VERSION/pngcrush-$PNGCRUSH_VERSION.tar.gz
|
122
|
+
tar zxf pngcrush-$PNGCRUSH_VERSION.tar.gz
|
123
|
+
cd pngcrush-$PNGCRUSH_VERSION
|
111
124
|
make && cp -f pngcrush /usr/local/bin
|
112
125
|
```
|
113
126
|
|
data/bin/image_optim
CHANGED
@@ -6,7 +6,7 @@ require 'image_optim/runner'
|
|
6
6
|
options = {}
|
7
7
|
|
8
8
|
option_parser = OptionParser.new do |op|
|
9
|
-
|
9
|
+
ImageOptim::TrueFalseNil.add_to_option_parser(op)
|
10
10
|
|
11
11
|
op.banner = <<-TEXT.gsub(/^\s*\|/, '')
|
12
12
|
|#{ImageOptim.full_version}
|
@@ -16,17 +16,19 @@ option_parser = OptionParser.new do |op|
|
|
16
16
|
|
|
17
17
|
|Configuration will be read and prepanded to options from two paths:
|
18
18
|
| #{ImageOptim::Config::GLOBAL_CONFIG_PATH}
|
19
|
-
| #{ImageOptim::Config::LOCAL_CONFIG_PATH}
|
19
|
+
| #{ImageOptim::Config::LOCAL_CONFIG_PATH}
|
20
20
|
|
|
21
21
|
TEXT
|
22
22
|
|
23
|
-
op.on('-r', '-R', '--recursive', 'Recurively scan directories
|
23
|
+
op.on('-r', '-R', '--recursive', 'Recurively scan directories '\
|
24
|
+
'for images') do |recursive|
|
24
25
|
options[:recursive] = recursive
|
25
26
|
end
|
26
27
|
|
27
28
|
op.separator nil
|
28
29
|
|
29
|
-
op.on('--[no-]threads N', Integer, 'Number of threads or disable
|
30
|
+
op.on('--[no-]threads N', Integer, 'Number of threads or disable '\
|
31
|
+
'(defaults to number of processors)') do |threads|
|
30
32
|
options[:threads] = threads
|
31
33
|
end
|
32
34
|
|
@@ -64,13 +66,18 @@ option_parser = OptionParser.new do |op|
|
|
64
66
|
when Array >= type
|
65
67
|
[Array, 'a,b,c']
|
66
68
|
else
|
67
|
-
|
69
|
+
fail "Unknown type #{type}"
|
68
70
|
end
|
69
71
|
|
70
|
-
|
71
|
-
|
72
|
+
description_lines = %W[
|
73
|
+
#{option_definition.description.gsub(' - ', ' - ')}
|
74
|
+
(defaults to #{default})
|
75
|
+
].join(' ').
|
76
|
+
scan(/.*?.{1,60}(?:\s|\z)/).
|
77
|
+
join("\n ").
|
78
|
+
split("\n")
|
72
79
|
|
73
|
-
op.on("--#{bin}-#{name} #{marking}", type, *
|
80
|
+
op.on("--#{bin}-#{name} #{marking}", type, *description_lines) do |value|
|
74
81
|
options[bin] = {} unless options[bin].is_a?(Hash)
|
75
82
|
options[bin][option_definition.name.to_sym] = value
|
76
83
|
end
|
@@ -98,18 +105,21 @@ end
|
|
98
105
|
begin
|
99
106
|
args = ARGV.dup
|
100
107
|
|
101
|
-
if
|
102
|
-
|
103
|
-
end
|
108
|
+
# assume -v to be request to print version if it is the only argument
|
109
|
+
args = %w[--version] if args == %w[-v]
|
104
110
|
|
105
111
|
option_parser.parse!(args)
|
106
|
-
|
107
|
-
|
112
|
+
if options[:verbose]
|
113
|
+
$stderr.puts ImageOptim.full_version
|
114
|
+
end
|
115
|
+
unless ImageOptim::Runner.run!(args, options)
|
116
|
+
abort
|
117
|
+
end
|
108
118
|
rescue OptionParser::ParseError => e
|
109
|
-
abort "#{e
|
119
|
+
abort "#{e}\n\n#{option_parser.help}"
|
110
120
|
rescue => e
|
111
121
|
if options[:verbose]
|
112
|
-
abort "#{e
|
122
|
+
abort "#{e}\n#{e.backtrace.join("\n")}"
|
113
123
|
else
|
114
124
|
abort e.to_s
|
115
125
|
end
|
data/image_optim.gemspec
CHANGED
@@ -2,7 +2,7 @@
|
|
2
2
|
|
3
3
|
Gem::Specification.new do |s|
|
4
4
|
s.name = 'image_optim'
|
5
|
-
s.version = '0.
|
5
|
+
s.version = '0.14.0'
|
6
6
|
s.summary = %q{Optimize (lossless compress) images (jpeg, png, gif, svg) using external utilities (advpng, gifsicle, jpegoptim, jpegtran, optipng, pngcrush, pngout, svgo)}
|
7
7
|
s.homepage = "http://github.com/toy/#{s.name}"
|
8
8
|
s.authors = ['Ivan Kuchin']
|
@@ -20,5 +20,8 @@ Gem::Specification.new do |s|
|
|
20
20
|
s.add_dependency 'exifr', '~> 1.1.3'
|
21
21
|
s.add_dependency 'progress', '~> 3.0.0'
|
22
22
|
s.add_dependency 'in_threads', '~> 1.2.0'
|
23
|
-
s.add_development_dependency 'rspec'
|
23
|
+
s.add_development_dependency 'rspec', '~> 3.0'
|
24
|
+
if Gem::Version.new(RUBY_VERSION) >= Gem::Version.new('1.9.2')
|
25
|
+
s.add_development_dependency 'rubocop', '~> 0.24.1'
|
26
|
+
end
|
24
27
|
end
|
data/lib/image_optim.rb
CHANGED
@@ -7,6 +7,7 @@ require 'image_optim/worker'
|
|
7
7
|
require 'in_threads'
|
8
8
|
require 'shellwords'
|
9
9
|
|
10
|
+
# Main interface
|
10
11
|
class ImageOptim
|
11
12
|
# Nice level
|
12
13
|
attr_reader :nice
|
@@ -15,9 +16,7 @@ class ImageOptim
|
|
15
16
|
attr_reader :threads
|
16
17
|
|
17
18
|
# Verbose output?
|
18
|
-
|
19
|
-
@verbose
|
20
|
-
end
|
19
|
+
attr_reader :verbose
|
21
20
|
|
22
21
|
# Initialize workers, specify options using worker underscored name:
|
23
22
|
#
|
@@ -29,11 +28,13 @@ class ImageOptim
|
|
29
28
|
#
|
30
29
|
# ImageOptim.new(:advpng => {:level => 3}, :optipng => {:level => 2})
|
31
30
|
#
|
32
|
-
# use :threads to set number of parallel optimizers to run (passing true or
|
31
|
+
# use :threads to set number of parallel optimizers to run (passing true or
|
32
|
+
# nil determines number of processors, false disables parallel processing)
|
33
33
|
#
|
34
34
|
# ImageOptim.new(:threads => 8)
|
35
35
|
#
|
36
|
-
# use :nice to specify optimizers nice level (true or nil makes it 10, false
|
36
|
+
# use :nice to specify optimizers nice level (true or nil makes it 10, false
|
37
|
+
# makes it 0)
|
37
38
|
#
|
38
39
|
# ImageOptim.new(:nice => 20)
|
39
40
|
def initialize(options = {})
|
@@ -42,7 +43,7 @@ class ImageOptim
|
|
42
43
|
@threads = config.threads
|
43
44
|
@verbose = config.verbose
|
44
45
|
|
45
|
-
if verbose
|
46
|
+
if verbose
|
46
47
|
$stderr << config
|
47
48
|
$stderr << "Nice level: #{nice}\n"
|
48
49
|
$stderr << "Using threads: #{threads}\n"
|
@@ -50,17 +51,9 @@ class ImageOptim
|
|
50
51
|
|
51
52
|
@bin_resolver = BinResolver.new(self)
|
52
53
|
|
53
|
-
@workers_by_format =
|
54
|
-
|
55
|
-
if worker_options = config.for_worker(klass)
|
56
|
-
worker = klass.new(self, worker_options)
|
57
|
-
worker.image_formats.each do |format|
|
58
|
-
@workers_by_format[format] ||= []
|
59
|
-
@workers_by_format[format] << worker
|
60
|
-
end
|
61
|
-
end
|
54
|
+
@workers_by_format = create_workers_by_format do |klass|
|
55
|
+
config.for_worker(klass)
|
62
56
|
end
|
63
|
-
@workers_by_format.values.each(&:sort!)
|
64
57
|
|
65
58
|
config.assert_no_unused_options!
|
66
59
|
end
|
@@ -70,30 +63,29 @@ class ImageOptim
|
|
70
63
|
@workers_by_format[ImagePath.convert(path).format]
|
71
64
|
end
|
72
65
|
|
73
|
-
# Optimize one file, return new path as OptimizedImagePath or nil if
|
66
|
+
# Optimize one file, return new path as OptimizedImagePath or nil if
|
67
|
+
# optimization failed
|
74
68
|
def optimize_image(original)
|
75
69
|
original = ImagePath.convert(original)
|
76
|
-
|
77
|
-
|
78
|
-
|
79
|
-
|
80
|
-
|
81
|
-
end
|
82
|
-
end
|
83
|
-
handler.cleanup
|
84
|
-
if handler.result
|
85
|
-
ImagePath::Optimized.new(handler.result, original)
|
70
|
+
return unless (workers = workers_for_image(original))
|
71
|
+
handler = Handler.new(original)
|
72
|
+
workers.each do |worker|
|
73
|
+
handler.process do |src, dst|
|
74
|
+
worker.optimize(src, dst)
|
86
75
|
end
|
87
76
|
end
|
77
|
+
handler.cleanup
|
78
|
+
return unless handler.result
|
79
|
+
ImagePath::Optimized.new(handler.result, original)
|
88
80
|
end
|
89
81
|
|
90
|
-
# Optimize one file in place, return original as OptimizedImagePath or nil if
|
82
|
+
# Optimize one file in place, return original as OptimizedImagePath or nil if
|
83
|
+
# optimization failed
|
91
84
|
def optimize_image!(original)
|
92
85
|
original = ImagePath.convert(original)
|
93
|
-
|
94
|
-
|
95
|
-
|
96
|
-
end
|
86
|
+
return unless (result = optimize_image(original))
|
87
|
+
result.replace(original)
|
88
|
+
ImagePath::Optimized.new(original, result.original_size)
|
97
89
|
end
|
98
90
|
|
99
91
|
# Optimize image data, return new data or nil if optimization failed
|
@@ -105,28 +97,31 @@ class ImageOptim
|
|
105
97
|
temp.write(original_data)
|
106
98
|
temp.close
|
107
99
|
|
108
|
-
if result = optimize_image(temp.path)
|
100
|
+
if (result = optimize_image(temp.path))
|
109
101
|
result.open('rb', &:read)
|
110
102
|
end
|
111
103
|
end
|
112
104
|
end
|
113
105
|
|
114
106
|
# Optimize multiple images
|
115
|
-
# if block given yields path and result for each image and returns array of
|
107
|
+
# if block given yields path and result for each image and returns array of
|
108
|
+
# yield results
|
116
109
|
# else return array of results
|
117
110
|
def optimize_images(paths, &block)
|
118
111
|
run_method_for(paths, :optimize_image, &block)
|
119
112
|
end
|
120
113
|
|
121
114
|
# Optimize multiple images in place
|
122
|
-
# if block given yields path and result for each image and returns array of
|
115
|
+
# if block given yields path and result for each image and returns array of
|
116
|
+
# yield results
|
123
117
|
# else return array of results
|
124
118
|
def optimize_images!(paths, &block)
|
125
119
|
run_method_for(paths, :optimize_image!, &block)
|
126
120
|
end
|
127
121
|
|
128
122
|
# Optimize multiple image datas
|
129
|
-
# if block given yields original and result for each image data and returns
|
123
|
+
# if block given yields original and result for each image data and returns
|
124
|
+
# array of yield results
|
130
125
|
# else return array of results
|
131
126
|
def optimize_images_data(datas, &block)
|
132
127
|
run_method_for(datas, :optimize_image_data, &block)
|
@@ -156,7 +151,8 @@ class ImageOptim
|
|
156
151
|
!!workers_for_image(path)
|
157
152
|
end
|
158
153
|
|
159
|
-
# Check existance of binary, create symlink if ENV contains path for key
|
154
|
+
# Check existance of binary, create symlink if ENV contains path for key
|
155
|
+
# XXX_BIN where XXX is upper case bin name
|
160
156
|
def resolve_bin!(bin)
|
161
157
|
@bin_resolver.resolve!(bin)
|
162
158
|
end
|
@@ -168,6 +164,20 @@ class ImageOptim
|
|
168
164
|
|
169
165
|
private
|
170
166
|
|
167
|
+
# Create hash with format mapped to list of workers sorted by run order
|
168
|
+
def create_workers_by_format(&options_proc)
|
169
|
+
by_format = {}
|
170
|
+
Worker.klasses.each do |klass|
|
171
|
+
next unless (options = options_proc[klass])
|
172
|
+
worker = klass.new(self, options)
|
173
|
+
worker.image_formats.each do |format|
|
174
|
+
by_format[format] ||= []
|
175
|
+
by_format[format] << worker
|
176
|
+
end
|
177
|
+
end
|
178
|
+
by_format.each{ |_format, workers| workers.sort! }
|
179
|
+
end
|
180
|
+
|
171
181
|
# Run method for each path and yield each path and result if block given
|
172
182
|
def run_method_for(paths, method_name, &block)
|
173
183
|
apply_threading(paths).map do |path|
|
@@ -7,7 +7,13 @@ class ImageOptim
|
|
7
7
|
class BinNotFoundError < StandardError; end
|
8
8
|
class BadBinVersion < StandardError; end
|
9
9
|
|
10
|
+
# Handles resolving binaries and checking versions
|
11
|
+
#
|
12
|
+
# If there is an environment variable XXX_BIN when resolbing xxx, then a
|
13
|
+
# symlink to binary will be created in a temporary directory which will be
|
14
|
+
# added to PATH
|
10
15
|
class BinResolver
|
16
|
+
# Holds name and version of an executable
|
11
17
|
class Bin
|
12
18
|
attr_reader :name, :version
|
13
19
|
def initialize(name, version)
|
@@ -31,8 +37,9 @@ class ImageOptim
|
|
31
37
|
name = name.to_sym
|
32
38
|
|
33
39
|
resolving(name) do
|
34
|
-
|
35
|
-
|
40
|
+
bin = Bin.new(name, version(name)) if resolve?(name)
|
41
|
+
if bin && @image_optim.verbose
|
42
|
+
$stderr << "Resolved #{bin}\n"
|
36
43
|
end
|
37
44
|
@bins[name] = bin
|
38
45
|
end
|
@@ -40,7 +47,7 @@ class ImageOptim
|
|
40
47
|
if @bins[name]
|
41
48
|
check!(@bins[name])
|
42
49
|
else
|
43
|
-
|
50
|
+
fail BinNotFoundError, "`#{name}` not found"
|
44
51
|
end
|
45
52
|
end
|
46
53
|
|
@@ -53,17 +60,14 @@ class ImageOptim
|
|
53
60
|
private
|
54
61
|
|
55
62
|
def resolving(name)
|
56
|
-
|
57
|
-
|
58
|
-
|
59
|
-
yield
|
60
|
-
end
|
61
|
-
end
|
63
|
+
return if @bins.include?(name)
|
64
|
+
@lock.synchronize do
|
65
|
+
yield unless @bins.include?(name)
|
62
66
|
end
|
63
67
|
end
|
64
68
|
|
65
69
|
def resolve?(name)
|
66
|
-
if path = ENV["#{name}_bin".upcase]
|
70
|
+
if (path = ENV["#{name}_bin".upcase])
|
67
71
|
unless @dir
|
68
72
|
@dir = FSPath.temp_dir
|
69
73
|
at_exit{ FileUtils.remove_entry_secure @dir }
|
@@ -91,7 +95,8 @@ class ImageOptim
|
|
91
95
|
when :pngcrush
|
92
96
|
capture_output("#{name} -version 2>&1")[/\d+(\.\d+){1,}/]
|
93
97
|
when :pngout
|
94
|
-
|
98
|
+
date_regexp = /[A-Z][a-z]{2} (?: |\d)\d \d{4}/
|
99
|
+
date_str = capture_output("#{name} 2>&1")[date_regexp]
|
95
100
|
Date.parse(date_str).strftime('%Y%m%d')
|
96
101
|
end
|
97
102
|
end
|
@@ -102,7 +107,7 @@ class ImageOptim
|
|
102
107
|
when :pngcrush
|
103
108
|
case bin.version
|
104
109
|
when c = is.between?('1.7.60', '1.7.65')
|
105
|
-
|
110
|
+
fail BadBinVersion, "`#{bin}` (#{c}) is known to produce broken pngs"
|
106
111
|
end
|
107
112
|
when :advpng
|
108
113
|
case bin.version
|