Skip to content
Browse files

More efficient system of hashes for versioning

  • Loading branch information...
1 parent 7326a08 commit 4931153ad100c10c2d24a145e264ab574927f30c @winton committed Dec 20, 2010
Showing with 74 additions and 76 deletions.
  1. +43 −41 lib/smart_asset.rb
  2. +2 −2 spec/fixtures/production_output.txt
  3. +29 −33 spec/smart_asset_spec.rb
View
84 lib/smart_asset.rb
@@ -2,6 +2,7 @@
SmartAsset::Gems.require(:lib)
+require 'digest'
require 'fileutils'
require 'time'
require 'yaml'
@@ -29,39 +30,46 @@ def binary(root, relative_config=nil)
def compress(type)
dest = @dest[type]
dir = "#{@pub}/#{@sources[type]}"
- ext = ext_from_type type
- version = {}
- cache = {}
-
- # Read version yaml
- if File.exists?(version_path = "#{dest}/#{type}.yml")
- version = YAML::load(File.read(version_path))
- end
+ ext = ext_from_type(type)
+ packages = []
+ time_cache = {}
FileUtils.mkdir_p dest
(@config[type] || {}).each do |package, files|
next if ENV['PACKAGE'] && ENV['PACKAGE'] != package
if files
# Retrieve list of Git modified timestamps
- modified = []
+ timestamps = []
files.each do |file|
- fname = "#{dir}/#{file}.#{ext}"
- if File.exists?(fname)
- mod = (cache[fname] ||= `cd #{@root} && git log --pretty=format:%cd -n 1 --date=iso #{@config['public']}/#{@sources[type]}/#{file}.#{ext}`)
- if mod.strip.empty? || mod.include?('command not found')
- modified << (ENV['MODIFIED'] ? Time.parse(ENV['MODIFIED']) : Time.now).utc.strftime("%Y%m%d%H%M%S")
+ if File.exists?("#{dir}/#{file}.#{ext}")
+ if time_cache[file]
+ time = time_cache[file]
else
- modified << Time.parse(mod).utc.strftime("%Y%m%d%H%M%S")
+ time = `cd #{@root} && git log --pretty=format:%cd -n 1 --date=iso #{@config['public']}/#{@sources[type]}/#{file}.#{ext}`
+ if time.strip.empty? || time.include?('command not found')
+ time = ENV['MODIFIED'] ? Time.parse(ENV['MODIFIED']) : Time.now
+ else
+ time = Time.parse(time)
+ end
+ time = time.utc.strftime("%Y%m%d%H%M%S")
+ time += file.to_s
+ time_cache[file] = time
end
+ timestamps << time
end
end
- modified = modified.sort.last
- next unless modified
+ next if timestamps.empty?
+
+ # Modified hash
+ hash = Digest::SHA1.hexdigest(timestamps.sort.join)[0..7]
- # If package changed or package file doesn't exist
- output = "#{dest}/#{modified}_#{package}.#{ext}"
- if version[package] != files || !File.exists?(output)
+ # Package path
+ package = "#{dest}/#{hash}_#{package}.#{ext}"
+ packages << package
+
+ # If package file does not exist
+ unless File.exists?(package)
data = []
# Join files in package
@@ -71,24 +79,20 @@ def compress(type)
end
end
- # Delete old package
- Dir["#{dest}/*[0-9]_#{package}.#{ext}"].each do |old|
- FileUtils.rm old
- end
-
# Don't create new compressed file if no data
- next if data.empty?
+ data = data.join("\n")
+ next if data.strip.empty?
# Compress joined files
tmp = "#{dest}/tmp.#{ext}"
- File.open(tmp, 'w') { |f| f.write(data.join("\n")) }
- puts "\nCreating #{output}..."
+ File.open(tmp, 'w') { |f| f.write(data) }
+ puts "\nCreating #{package}..."
if ext == 'js'
warning = ENV['WARN'] ? nil : " --warning_level QUIET"
- cmd = "java -jar #{CLOSURE_COMPILER} --js #{tmp} --js_output_file #{output}#{warning}"
+ cmd = "java -jar #{CLOSURE_COMPILER} --js #{tmp} --js_output_file #{package}#{warning}"
elsif ext == 'css'
warning = ENV['WARN'] ? " -v" : nil
- cmd = "java -jar #{YUI_COMPRESSOR} #{tmp} -o #{output}#{warning}"
+ cmd = "java -jar #{YUI_COMPRESSOR} #{tmp} -o #{package}#{warning}"
end
puts cmd if ENV['DEBUG']
`#{cmd}`
@@ -97,25 +101,23 @@ def compress(type)
# Fix YUI compression issue
if ext == 'css'
if RUBY_PLATFORM.downcase.include?('darwin')
- `sed -i '' 's/ and(/ and (/g' #{output}`
+ `sed -i '' 's/ and(/ and (/g' #{package}`
else
- `sed -i 's/ and(/ and (/g' #{output}`
+ `sed -i 's/ and(/ and (/g' #{package}`
end
end
end
end
end
- # Delete removed packages
- (version.keys - (@config[type] || {}).keys).each do |package|
- Dir["#{dest}/*[0-9]_#{package}.#{ext}"].each do |old|
- FileUtils.rm old
- end
+ # Remove old/unused packages
+ (Dir["#{dest}/????????_*.#{ext}"] - packages).each do |path|
+ FileUtils.rm path
end
- # Write version yaml file
- if @config[type]
- File.open(version_path, 'w') { |f| f.write(YAML::dump(@config[type])) }
+ # Delete legacy yml files
+ Dir["#{dest}/*.yml"].each do |path|
+ FileUtils.rm path
end
end
@@ -188,7 +190,7 @@ def paths(type, match)
if @envs.include?(@env.to_s)
@cache[type][match] =
- if result = Dir["#{dest}/*[0-9]_#{match}.#{ext}"].sort.last
+ if result = Dir["#{dest}/????????_#{match}.#{ext}"].sort.last
[ result.gsub(@pub, '') ]
else
[]
View
4 spec/fixtures/production_output.txt
@@ -1,3 +1,3 @@
-<script src="/packaged/20101130061253_package.js"></script>
+<script src="/packaged/91d1e5c5_package.js"></script>
-<link href="/packaged/20101130061253_package.css" media="screen" rel="stylesheet" />
+<link href="/packaged/4c0f7deb_package.css" media="screen" rel="stylesheet" />
View
62 spec/smart_asset_spec.rb
@@ -8,14 +8,13 @@
before(:all) do
@config = "spec/fixtures/assets.yml"
@dest = "#{$root}/spec/fixtures/assets/compressed"
- @old_version = '20101130061252'
@files = %w(
package.css
package.js
)
@versions = %w(
- 20101210234715
- 20101130061253
+ 4c0f7deb
+ 91d1e5c5
)
end
@@ -93,11 +92,6 @@
it "should generate correct filenames" do
@files.each_with_index do |file, i|
- unless File.exists?("#{@dest}/#{@versions[i]}_#{file}")
- puts "#{@dest}/#{@versions[i]}_#{file}".inspect
- exit
- end
-
File.exists?("#{@dest}/#{@versions[i]}_#{file}").should == true
end
Dir["#{@dest}/*.{js,css}"].length.should == @files.length
@@ -130,25 +124,25 @@
File.read("#{@dest}/#{@versions[0]}_#{@files[0]}").include?("screen and (").should == true
end
end
-
+
describe 'one version out of date' do
-
+
before(:all) do
unless ENV['FAST']
- FileUtils.mv "#{@dest}/#{@versions[0]}_#{@files[0]}", "#{@dest}/#{@old_version}_#{@files[0]}"
+ FileUtils.mv "#{@dest}/#{@versions[0]}_#{@files[0]}", "#{@dest}/00000000_#{@files[0]}"
end
@output = capture_stdout do
SmartAsset.binary $root, @config
end
end
-
+
it "should generate correct filenames" do
@files.each_with_index do |file, i|
File.exists?("#{@dest}/#{@versions[i]}_#{file}").should == true
end
Dir["#{@dest}/*.{js,css}"].length.should == @files.length
end
-
+
it "should create package files with content" do
@files.each_with_index do |file, i|
File.size(path = "#{@dest}/#{@versions[i]}_#{file}").should > 0
@@ -164,6 +158,10 @@
end
end
+ it "should remove old version" do
+ Dir["#{@dest}/*.css"].length.should == 1
+ end
+
unless ENV['FAST']
it "should run updated file through the compressor" do
@files.each_with_index do |file, i|
@@ -178,14 +176,11 @@
before(:all) do
@package_config = SmartAsset.config['javascripts']['package']
- @old_version_path = "#{@dest}/javascripts.yml"
- @old_version = File.read(@old_version_path)
@old_package_path = "#{@dest}/#{@versions[1]}_#{@files[1]}"
@old_package = File.read(@old_package_path)
end
after(:all) do
- File.open(@old_version_path, 'w') { |f| f.write(@old_version) }
File.open(@old_package_path, 'w') { |f| f.write(@old_package) }
end
@@ -203,28 +198,26 @@
end
it "should rewrite javascript package with only jquery" do
- @files.each_with_index do |file, i|
- File.size(path = "#{@dest}/#{@versions[i]}_#{file}").should > 0
- if i == 1
- js = File.read(path)
- js.include?('jQuery').should == true
- js.include?('VERSION').should == false
- end
- end
+ File.size(path = "#{@dest}/b00ce510_#{@files[1]}").should > 0
+ js = File.read(path)
+ js.include?('jQuery').should == true
+ js.include?('VERSION').should == false
end
it "should run updated file through the compressor" do
@files.each_with_index do |file, i|
@output.string.include?(file).should == (i == 1 ? true : false)
end
end
+
+ it "should remove old version" do
+ Dir["#{@dest}/*.js"].length.should == 1
+ end
end
describe 'package removed' do
before(:all) do
- @old_version_path = "#{@dest}/javascripts.yml"
- @old_version = File.read(@old_version_path)
@old_package_path = "#{@dest}/#{@versions[1]}_#{@files[1]}"
@old_package = File.read(@old_package_path)
@@ -235,22 +228,21 @@
end
after(:all) do
- File.open(@old_version_path, 'w') { |f| f.write(@old_version) }
File.open(@old_package_path, 'w') { |f| f.write(@old_package) }
end
it "should delete the javascript package" do
- File.exists?("#{@dest}/#{@versions[1]}_#{@files[1]}").should == false
+ Dir["#{@dest}/*.js"].length.should == 0
end
end
describe 'untracked file' do
before(:all) do
- @modified = Time.now.utc
+ @modified = Time.parse('12-01-2010').utc
ENV['MODIFIED'] = @modified.to_s
- @package = "#{@dest}/#{@modified.strftime("%Y%m%d%H%M%S")}_#{@files[1]}"
- @untracked = "#{@dest}/untracked.js"
+ @package = "#{@dest}/8166ebb0_#{@files[1]}"
+ @untracked = "#{$root}/spec/fixtures/assets/javascripts/untracked.js"
File.open(@untracked, 'w') { |f| f.write("var untracked = true;") }
SmartAsset.config['javascripts']['package'] << 'untracked'
@@ -266,11 +258,15 @@
end
it "should create package with default modified time" do
- File.exists?(@untracked).should == true
+ File.exists?(@package).should == true
end
it "should create package with untracked file" do
- File.read(@untracked).include?('var untracked').should == true
+ File.read(@package).include?('var untracked').should == true
+ end
+
+ it "should remove old version" do
+ Dir["#{@dest}/*.js"].length.should == 1
end
end
end

0 comments on commit 4931153

Please sign in to comment.
Something went wrong with that request. Please try again.