diff --git a/README.md b/README.md index 26249a0..e5649da 100644 --- a/README.md +++ b/README.md @@ -136,7 +136,15 @@ Or add to a traditional unix system * **aws\_access\_key**: your Amazon S3 access key * **aws\_access\_secret**: your Amazon S3 access secret * **aws\_region**: the region your S3 bucket is in e.g. *eu-west-1* -* **existing_remote_files**: what to do with previously precompiled files, options are **keep** or **delete** +* **existing\_remote\_files**: what to do with previously precompiled files, options are **keep** or **delete** +* **gzip\_compression**: when enabled, will automatically replace files that have a gzip compressed equivalent with the compressed version. + +## Automatic gzip compression + +With the `gzip_compression` option enabled, when uploading your assets. If a file has a gzip compressed equivalent we will replace that asset with the compressed version and sets the correct headers for S3 to serve it. For example, if you have a file **master.css** and it was compressed to **master.css.gz** we will upload the **.gz** file to S3 in place of the uncompressed file. + +If the compressed file is actually larger than the uncompressed file we will ignore this rule and upload the standard uncompressed version. + ## Amazon S3 Multiple Region Support diff --git a/asset_sync.gemspec b/asset_sync.gemspec index 5651b5a..049937f 100644 --- a/asset_sync.gemspec +++ b/asset_sync.gemspec @@ -6,12 +6,12 @@ require "asset_sync/version" Gem::Specification.new do |s| s.name = "asset_sync" s.version = AssetSync::VERSION - s.date = "2011-08-30" + s.date = "2011-11-05" s.platform = Gem::Platform::RUBY s.authors = ["Simon Hamilton", "David Rice"] s.email = ["shamilton@rumblelabs.com", "me@davidjrice.co.uk"] s.homepage = "https://github.com/rumblelabs/asset_sync" - s.summary = %q{Synchronises Assets between Rails and S3} + s.summary = %q{Synchronises Assets in a Rails 3 application and S3/Cloudfront} s.description = %q{After you run assets:precompile your assets will be synchronised with your S3 bucket, deleting unused files and only uploading the files it needs to.} s.rubyforge_project = "asset_sync" diff --git a/lib/asset_sync/config.rb b/lib/asset_sync/config.rb index 6162fdf..8735f68 100644 --- a/lib/asset_sync/config.rb +++ b/lib/asset_sync/config.rb @@ -9,6 +9,7 @@ class Invalid < StandardError; end attr_accessor :aws_bucket attr_accessor :aws_region attr_accessor :existing_remote_files + attr_accessor :gzip_compression validates :aws_access_key, :presence => true validates :aws_access_secret, :presence => true @@ -19,9 +20,14 @@ def initialize self.provider = 'AWS' self.aws_region = nil self.existing_remote_files = 'keep' + self.gzip_compression = false load_yml! if yml_exists? end + def gzip? + self.gzip_compression + end + def existing_remote_files? (self.existing_remote_files == "keep") end @@ -45,6 +51,7 @@ def load_yml! self.aws_bucket = yml["aws_bucket"] if yml.has_key?("aws_bucket") self.aws_region = yml["aws_region"] if yml.has_key?("aws_region") self.existing_remote_files = yml["existing_remote_files"] if yml.has_key?("existing_remote_files") + self.gzip_compression = yml["gzip_compression"] if yml.has_key?("gzip_compression") # TODO deprecate old style config settings self.aws_access_key = yml["access_key_id"] if yml.has_key?("access_key_id") diff --git a/lib/asset_sync/storage.rb b/lib/asset_sync/storage.rb index f78b202..0c65343 100644 --- a/lib/asset_sync/storage.rb +++ b/lib/asset_sync/storage.rb @@ -54,13 +54,46 @@ def delete_extra_remote_files end def upload_file(f) - STDERR.puts "Uploading: #{f}" - file = bucket.files.create( - :key => "#{f}", + # TODO output files in debug logs as asset filename only. + file = { + :key => f, :body => File.open("#{path}/#{f}"), :public => true, :cache_control => "max-age=31557600" - ) + } + + gzipped = "#{path}/#{f}.gz" + ignore = false + + if config.gzip? && File.extname(f) == ".gz" + # Don't bother uploading gzipped assets if we are in gzip_compression mode + # as we will overwrite file.css with file.css.gz if it exists. + STDERR.puts "Ignoring: #{f}" + ignore = true + elsif config.gzip? && File.exists?(gzipped) + original_size = File.size("#{path}/#{f}") + gzipped_size = File.size(gzipped) + + if gzipped_size < original_size + percentage = ((gzipped_size.to_f/original_size.to_f)*100).round(2) + ext = File.extname( f )[1..-1] + mime = Mime::Type.lookup_by_extension( ext ) + file.merge!({ + :key => f, + :body => File.open(gzipped), + :content_type => mime, + :content_encoding => 'gzip' + }) + STDERR.puts "Uploading: #{gzipped} in place of #{f} saving #{percentage}%" + else + percentage = ((original_size.to_f/gzipped_size.to_f)*100).round(2) + STDERR.puts "Uploading: #{f} instead of #{gzipped} (compression increases this file by #{percentage}%)" + end + else + STDERR.puts "Uploading: #{f}" + end + + file = bucket.files.create( file ) unless ignore end def upload_files diff --git a/lib/asset_sync/version.rb b/lib/asset_sync/version.rb index b713a98..917fbbb 100644 --- a/lib/asset_sync/version.rb +++ b/lib/asset_sync/version.rb @@ -1,3 +1,3 @@ module AssetSync - VERSION = "0.1.8" + VERSION = "0.1.9" end diff --git a/lib/generators/asset_sync/templates/asset_sync.rb b/lib/generators/asset_sync/templates/asset_sync.rb index 2a24e5f..9634cbc 100644 --- a/lib/generators/asset_sync/templates/asset_sync.rb +++ b/lib/generators/asset_sync/templates/asset_sync.rb @@ -2,6 +2,9 @@ config.aws_access_key = ENV['AWS_ACCESS_KEY'] config.aws_access_secret = ENV['AWS_ACCESS_SECRET'] config.aws_bucket = ENV['AWS_BUCKET'] - # config.aws_region = "eu-west-1" config.existing_remote_files = "keep" + # Increase upload performance by configuring your region + # config.aws_region = "eu-west-1" + # Automatically replace files with their equivalent gzip compressed version + # config.gzip_compression = true end \ No newline at end of file diff --git a/lib/generators/asset_sync/templates/asset_sync.yml b/lib/generators/asset_sync/templates/asset_sync.yml index 9770f2a..8213020 100644 --- a/lib/generators/asset_sync/templates/asset_sync.yml +++ b/lib/generators/asset_sync/templates/asset_sync.yml @@ -1,27 +1,30 @@ defaults: &defaults - access_key_id: "<%= aws_access_key %>" - secret_access_key: "<%= aws_access_secret %>" + aws_access_key: "<%= aws_access_key %>" + aws_access_secret: "<%= aws_access_secret %>" # You may need to specify what region your S3 bucket is in - # region: "eu-west-1" + # aws_region: "eu-west-1" existing_remote_files: keep + # Automatically replace files with their equivalent gzip compressed version + # gzip_compression = true + development: <<: *defaults - bucket: "<%= app_name %>_development" + aws_bucket: "<%= app_name %>_development" # Existing pre-compiled assets on S3 will be kept # existing_remote_files: keep test: <<: *defaults - bucket: "<%= app_name %>_test" + aws_bucket: "<%= app_name %>_test" staging: <<: *defaults - bucket: "<%= app_name %>_test" + aws_bucket: "<%= app_name %>_test" production: <<: *defaults - bucket: "<%= app_name %>_production" + aws_bucket: "<%= app_name %>_production" # Existing pre-compiled assets on S3 will be deleted # existing_remote_files: delete diff --git a/spec/asset_sync_spec.rb b/spec/asset_sync_spec.rb index 1a81aa1..0707790 100644 --- a/spec/asset_sync_spec.rb +++ b/spec/asset_sync_spec.rb @@ -39,6 +39,10 @@ AssetSync.config.existing_remote_files.should == "keep" end + it "should default gzip_compression to false" do + AssetSync.config.gzip_compression.should be_false + end + end @@ -69,6 +73,10 @@ AssetSync.config.existing_remote_files.should == "keep" end + it "should default gzip_compression to false" do + AssetSync.config.gzip_compression.should be_false + end + end describe AssetSync, 'with no configuration' do @@ -82,4 +90,18 @@ lambda{ AssetSync.sync }.should raise_error(AssetSync::Config::Invalid) end +end + +describe AssetSync, 'with gzip_compression enabled' do + + before(:all) do + Rails.root = 'without_yml' + AssetSync.config = AssetSync::Config.new + AssetSync.config.gzip_compression = true + end + + it "config.gzip? should be true" do + AssetSync.config.gzip?.should be_true + end + end \ No newline at end of file