Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with
or
.
Download ZIP
Newer
Older
100644 246 lines (205 sloc) 7.449 kB
7355d60 @winton First commit (smart_asset)
authored
1 require File.dirname(__FILE__) + '/smart_asset/gems'
2
3 SmartAsset::Gems.require(:lib)
4
4931153 @winton More efficient system of hashes for versioning
authored
5 require 'digest'
f2b3dcb @winton Compression working
authored
6 require 'fileutils'
7 require 'time'
1db5510 @winton Specs passing for Rails 2, Rails 3, Sinatra 1
authored
8 require 'yaml'
f2b3dcb @winton Compression working
authored
9
7a93efa @winton Making require paths less generic
authored
10 $:.unshift File.dirname(__FILE__)
7355d60 @winton First commit (smart_asset)
authored
11
7a93efa @winton Making require paths less generic
authored
12 require 'smart_asset/helper'
13 require 'smart_asset/version'
7355d60 @winton First commit (smart_asset)
authored
14
15 class SmartAsset
16 class <<self
17
d19b2b2 @winton Adding append_random option, fixing specs
authored
18 attr_accessor :append_random, :asset_host, :asset_counter, :cache, :config, :dest, :env, :envs, :pub, :root, :sources
7355d60 @winton First commit (smart_asset)
authored
19
1db5510 @winton Specs passing for Rails 2, Rails 3, Sinatra 1
authored
20 BIN = File.expand_path(File.dirname(__FILE__) + '/../bin')
21 CLOSURE_COMPILER = BIN + '/closure_compiler.jar'
22 YUI_COMPRESSOR = BIN + '/yui_compressor.jar'
f2b3dcb @winton Compression working
authored
23
1db5510 @winton Specs passing for Rails 2, Rails 3, Sinatra 1
authored
24 def binary(root, relative_config=nil)
7355d60 @winton First commit (smart_asset)
authored
25 load_config root, relative_config
1db5510 @winton Specs passing for Rails 2, Rails 3, Sinatra 1
authored
26 compress 'javascripts'
27 compress 'stylesheets'
f2b3dcb @winton Compression working
authored
28 end
29
1db5510 @winton Specs passing for Rails 2, Rails 3, Sinatra 1
authored
30 def compress(type)
735bce8 @winton Configurable destination paths
authored
31 dest = @dest[type]
1db5510 @winton Specs passing for Rails 2, Rails 3, Sinatra 1
authored
32 dir = "#{@pub}/#{@sources[type]}"
4931153 @winton More efficient system of hashes for versioning
authored
33 ext = ext_from_type(type)
34 packages = []
35 time_cache = {}
bb6d665 @winton Updating packages when config changes, deleting old packages when rem…
authored
36
735bce8 @winton Configurable destination paths
authored
37 FileUtils.mkdir_p dest
bb6d665 @winton Updating packages when config changes, deleting old packages when rem…
authored
38
1db5510 @winton Specs passing for Rails 2, Rails 3, Sinatra 1
authored
39 (@config[type] || {}).each do |package, files|
f329e49 @winton Adding PACKAGE option to specify a package name, adding line break be…
authored
40 next if ENV['PACKAGE'] && ENV['PACKAGE'] != package
1db5510 @winton Specs passing for Rails 2, Rails 3, Sinatra 1
authored
41 if files
8baadfa @winton Simplifying scope of project...no longer compressing every file, no l…
authored
42 # Retrieve list of Git modified timestamps
4931153 @winton More efficient system of hashes for versioning
authored
43 timestamps = []
1db5510 @winton Specs passing for Rails 2, Rails 3, Sinatra 1
authored
44 files.each do |file|
4931153 @winton More efficient system of hashes for versioning
authored
45 if File.exists?("#{dir}/#{file}.#{ext}")
46 if time_cache[file]
47 time = time_cache[file]
357545d @winton Adding asset_host support (picks up from Rails if not specified), spe…
authored
48 else
4931153 @winton More efficient system of hashes for versioning
authored
49 time = `cd #{@root} && git log --pretty=format:%cd -n 1 --date=iso #{@config['public']}/#{@sources[type]}/#{file}.#{ext}`
50 if time.strip.empty? || time.include?('command not found')
51 time = ENV['MODIFIED'] ? Time.parse(ENV['MODIFIED']) : Time.now
52 else
53 time = Time.parse(time)
54 end
55 time = time.utc.strftime("%Y%m%d%H%M%S")
56 time += file.to_s
57 time_cache[file] = time
357545d @winton Adding asset_host support (picks up from Rails if not specified), spe…
authored
58 end
4931153 @winton More efficient system of hashes for versioning
authored
59 timestamps << time
f2b3dcb @winton Compression working
authored
60 end
61 end
4931153 @winton More efficient system of hashes for versioning
authored
62 next if timestamps.empty?
63
64 # Modified hash
6484adb @winton Don't sort timestamps so changes in order will force repackage
authored
65 hash = Digest::SHA1.hexdigest(timestamps.join)[0..7]
8baadfa @winton Simplifying scope of project...no longer compressing every file, no l…
authored
66
4931153 @winton More efficient system of hashes for versioning
authored
67 # Package path
68 package = "#{dest}/#{hash}_#{package}.#{ext}"
69 packages << package
70
71 # If package file does not exist
72 unless File.exists?(package)
8baadfa @winton Simplifying scope of project...no longer compressing every file, no l…
authored
73 data = []
74
75 # Join files in package
76 files.each do |file|
77 if File.exists?(source = "#{dir}/#{file}.#{ext}")
78 data << File.read(source)
f2b3dcb @winton Compression working
authored
79 end
7355d60 @winton First commit (smart_asset)
authored
80 end
8baadfa @winton Simplifying scope of project...no longer compressing every file, no l…
authored
81
82 # Don't create new compressed file if no data
4931153 @winton More efficient system of hashes for versioning
authored
83 data = data.join("\n")
84 next if data.strip.empty?
8baadfa @winton Simplifying scope of project...no longer compressing every file, no l…
authored
85
86 # Compress joined files
87 tmp = "#{dest}/tmp.#{ext}"
4931153 @winton More efficient system of hashes for versioning
authored
88 File.open(tmp, 'w') { |f| f.write(data) }
89 puts "\nCreating #{package}..."
8baadfa @winton Simplifying scope of project...no longer compressing every file, no l…
authored
90 if ext == 'js'
91 warning = ENV['WARN'] ? nil : " --warning_level QUIET"
4931153 @winton More efficient system of hashes for versioning
authored
92 cmd = "java -jar #{CLOSURE_COMPILER} --js #{tmp} --js_output_file #{package}#{warning}"
8baadfa @winton Simplifying scope of project...no longer compressing every file, no l…
authored
93 elsif ext == 'css'
1754371 @winton Enabling WARN option for YUI Compressor
authored
94 warning = ENV['WARN'] ? " -v" : nil
4931153 @winton More efficient system of hashes for versioning
authored
95 cmd = "java -jar #{YUI_COMPRESSOR} #{tmp} -o #{package}#{warning}"
8baadfa @winton Simplifying scope of project...no longer compressing every file, no l…
authored
96 end
97 puts cmd if ENV['DEBUG']
98 `#{cmd}`
f329e49 @winton Adding PACKAGE option to specify a package name, adding line break be…
authored
99 FileUtils.rm(tmp) unless ENV['DEBUG']
8415086 @winton Fixing YUI compression issue, " and (" becomes " and("
authored
100
101 # Fix YUI compression issue
102 if ext == 'css'
103 if RUBY_PLATFORM.downcase.include?('darwin')
4931153 @winton More efficient system of hashes for versioning
authored
104 `sed -i '' 's/ and(/ and (/g' #{package}`
8415086 @winton Fixing YUI compression issue, " and (" becomes " and("
authored
105 else
4931153 @winton More efficient system of hashes for versioning
authored
106 `sed -i 's/ and(/ and (/g' #{package}`
8415086 @winton Fixing YUI compression issue, " and (" becomes " and("
authored
107 end
108 end
7355d60 @winton First commit (smart_asset)
authored
109 end
110 end
111 end
bb6d665 @winton Updating packages when config changes, deleting old packages when rem…
authored
112
4931153 @winton More efficient system of hashes for versioning
authored
113 # Remove old/unused packages
114 (Dir["#{dest}/????????_*.#{ext}"] - packages).each do |path|
115 FileUtils.rm path
bb6d665 @winton Updating packages when config changes, deleting old packages when rem…
authored
116 end
117
4931153 @winton More efficient system of hashes for versioning
authored
118 # Delete legacy yml files
119 Dir["#{dest}/*.yml"].each do |path|
120 FileUtils.rm path
bb6d665 @winton Updating packages when config changes, deleting old packages when rem…
authored
121 end
7355d60 @winton First commit (smart_asset)
authored
122 end
123
1db5510 @winton Specs passing for Rails 2, Rails 3, Sinatra 1
authored
124 def load_config(root, relative_config=nil)
125 relative_config ||= 'config/assets.yml'
7355d60 @winton First commit (smart_asset)
authored
126 @root = File.expand_path(root)
127 @config = YAML::load(File.read("#{@root}/#{relative_config}"))
1db5510 @winton Specs passing for Rails 2, Rails 3, Sinatra 1
authored
128
4210530 @winton Making the append_random option configurable by environment
authored
129 # Default values
d19b2b2 @winton Adding append_random option, fixing specs
authored
130 if @config['append_random'].nil?
4210530 @winton Making the append_random option configurable by environment
authored
131 @config['append_random'] = {}
d19b2b2 @winton Adding append_random option, fixing specs
authored
132 end
4d9423b @winton Fix for setting append_random config to true or false
authored
133 if @config['append_random'].is_a?(::Hash) && @config['append_random']['development'].nil?
4210530 @winton Making the append_random option configurable by environment
authored
134 @config['append_random']['development'] = true
135 end
136
26a5146 @winton Fixing asset_host numbering, adding asset_host_count config option
authored
137 @config['asset_host_count'] ||= 4
357545d @winton Adding asset_host support (picks up from Rails if not specified), spe…
authored
138 @config['asset_host'] ||= ActionController::Base.asset_host rescue nil
47466f8 @winton Fixing problems with package naming collisions, adding ability to spe…
authored
139 @config['environments'] ||= %w(production)
1db5510 @winton Specs passing for Rails 2, Rails 3, Sinatra 1
authored
140 @config['public'] ||= 'public'
4210530 @winton Making the append_random option configurable by environment
authored
141
735bce8 @winton Configurable destination paths
authored
142 @config['destination'] ||= {}
143 @config['destination']['javascripts'] ||= 'javascripts/packaged'
144 @config['destination']['stylesheets'] ||= 'stylesheets/packaged'
4210530 @winton Making the append_random option configurable by environment
authored
145
1db5510 @winton Specs passing for Rails 2, Rails 3, Sinatra 1
authored
146 @config['sources'] ||= {}
147 @config['sources']['javascripts'] ||= "javascripts"
148 @config['sources']['stylesheets'] ||= "stylesheets"
149
e4961d7 @winton Convert from asset packager style syntax
authored
150 # Convert from asset packager syntax
151 %w(javascripts stylesheets).each do |type|
152 if @config[type].respond_to?(:pop)
735bce8 @winton Configurable destination paths
authored
153 @config[type] = @config[type].inject({}) do |hash, package|
e4961d7 @winton Convert from asset packager style syntax
authored
154 hash.merge! package
155 end
156 end
157 end
158
4210530 @winton Making the append_random option configurable by environment
authored
159 # Class variables
160 @append_random =
161 if @config['append_random'].is_a?(::Hash)
162 @config['append_random'][@env]
163 else
164 @config['append_random']
165 end
166
357545d @winton Adding asset_host support (picks up from Rails if not specified), spe…
authored
167 @asset_host = @config['asset_host']
47466f8 @winton Fixing problems with package naming collisions, adding ability to spe…
authored
168 @envs = @config['environments']
357545d @winton Adding asset_host support (picks up from Rails if not specified), spe…
authored
169 @sources = @config['sources']
170
1db5510 @winton Specs passing for Rails 2, Rails 3, Sinatra 1
authored
171 @pub = File.expand_path("#{@root}/#{@config['public']}")
735bce8 @winton Configurable destination paths
authored
172 @dest = %w(javascripts stylesheets).inject({}) do |hash, type|
173 hash[type] = "#{@pub}/#{@config['destination'][type]}"
174 hash
175 end
1db5510 @winton Specs passing for Rails 2, Rails 3, Sinatra 1
authored
176 end
177
178 def paths(type, match)
179 match = match.to_s
180
181 @cache ||= {}
182 @cache[type] ||= {}
183
184 if @cache[type][match]
357545d @winton Adding asset_host support (picks up from Rails if not specified), spe…
authored
185 return @cache[type][match]
186 end
187
735bce8 @winton Configurable destination paths
authored
188 dest = @dest[type]
357545d @winton Adding asset_host support (picks up from Rails if not specified), spe…
authored
189 ext = ext_from_type type
190
47466f8 @winton Fixing problems with package naming collisions, adding ability to spe…
authored
191 if @envs.include?(@env.to_s)
1db5510 @winton Specs passing for Rails 2, Rails 3, Sinatra 1
authored
192 @cache[type][match] =
4931153 @winton More efficient system of hashes for versioning
authored
193 if result = Dir["#{dest}/????????_#{match}.#{ext}"].sort.last
26a5146 @winton Fixing asset_host numbering, adding asset_host_count config option
authored
194 [ result.gsub(@pub, '') ]
1db5510 @winton Specs passing for Rails 2, Rails 3, Sinatra 1
authored
195 else
196 []
197 end
198 elsif @config && @config[type]
199 result = @config[type].collect do |package, files|
200 if package.to_s == match
201 files.collect do |file|
202 file = "/#{@sources[type]}/#{file}.#{ext}"
26a5146 @winton Fixing asset_host numbering, adding asset_host_count config option
authored
203 file if File.exists?("#{@pub}/#{file}")
1db5510 @winton Specs passing for Rails 2, Rails 3, Sinatra 1
authored
204 end
205 end
206 end
207 result.flatten.compact.uniq
208 end
209 end
210
26a5146 @winton Fixing asset_host numbering, adding asset_host_count config option
authored
211 def prepend_asset_host(path)
212 if @asset_host.respond_to?(:keys)
213 host = @asset_host[@env.to_s]
214 else
215 host = @asset_host
216 end
217
218 if host
219 if !@asset_counter || @asset_counter == @config['asset_host_count']
220 @asset_counter = 0
221 end
222
223 count = @asset_counter.to_s
224 @asset_counter += 1
225
226 host.gsub('%d', count) + path
227 else
228 path
229 end
230 end
231
1db5510 @winton Specs passing for Rails 2, Rails 3, Sinatra 1
authored
232 private
233
234 def ext_from_type(type)
235 case type
236 when 'javascripts' then
237 'js'
238 when 'stylesheets' then
239 'css'
240 end
7355d60 @winton First commit (smart_asset)
authored
241 end
242 end
243 end
244
017dceb @winton Fixing require paths (again)
authored
245 require "smart_asset/adapters/rails#{Rails.version[0..0]}" if defined?(Rails)
246 require "smart_asset/adapters/sinatra" if defined?(Sinatra)
Something went wrong with that request. Please try again.