Skip to content
This repository

HTTPS clone URL

Subversion checkout URL

You can clone with HTTPS or Subversion.

Download ZIP
tree: 19d633f99e
Fetching contributors…

Cannot retrieve contributors at this time

file 150 lines (118 sloc) 4.598 kb
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150
require 'right_aws'
require 'tempfile'

module CloudfrontAssetHost
  module Uploader

    class << self

      def upload!(options = {})
        puts "-- Updating uncompressed files" if options[:verbose]
        upload_keys_with_paths(keys_with_paths, options)

        if CloudfrontAssetHost.gzip
          puts "-- Updating compressed files" if options[:verbose]
          upload_keys_with_paths(gzip_keys_with_paths, options.merge(:gzip => true))
        end

        @existing_keys = nil
      end

      def upload_keys_with_paths(keys_paths, options={})
        gzip = options[:gzip] || false
        dryrun = options[:dryrun] || false
        verbose = options[:verbose] || false

        keys_paths.each do |key, path|
          if should_upload?(key, options)
            puts "+ #{key}" if verbose

            extension = File.extname(path)[1..-1]

            path = rewritten_css_path(path)

            data_path = gzip ? gzipped_path(path) : path
            bucket.put(key, File.read(data_path), {}, 'public-read', headers_for_path(extension, gzip)) unless dryrun

            File.unlink(data_path) if gzip && File.exists?(data_path)
          else
            puts "= #{key}" if verbose
          end
        end
      end

      def should_upload?(key, options={})
        return false if CloudfrontAssetHost.disable_cdn_for_source?(key)
        return true if CloudfrontAssetHost.css?(key) && rewrite_all_css?

        options[:force_write] || !existing_keys.include?(key)
      end

      def gzipped_path(path)
        tmp = Tempfile.new("cfah-gz")
        `gzip '#{path}' -q -c > '#{tmp.path}'`
        tmp.path
      end

      def rewritten_css_path(path)
        if CloudfrontAssetHost.css?(path)
          tmp = CloudfrontAssetHost::CssRewriter.rewrite_stylesheet(path)
          tmp.path
        else
          path
        end
      end

      def keys_with_paths
        current_paths.inject({}) do |result, path|
          key = CloudfrontAssetHost.plain_prefix.present? ? "#{CloudfrontAssetHost.plain_prefix}/" : ""
          key << CloudfrontAssetHost.key_for_path(path) + path.gsub(Rails.public_path, '')

          result[key] = path
          result
        end
      end

      def gzip_keys_with_paths
        current_paths.inject({}) do |result, path|
          source = path.gsub(Rails.public_path, '')

          if CloudfrontAssetHost.gzip_allowed_for_source?(source)
            key = "#{CloudfrontAssetHost.gzip_prefix}/" << CloudfrontAssetHost.key_for_path(path) << source
            result[key] = path
          end

          result
        end
      end

      def rewrite_all_css?
        @rewrite_all_css ||= !keys_with_paths.delete_if { |key, path| existing_keys.include?(key) || !CloudfrontAssetHost.image?(path) }.empty?
      end

      def existing_keys
        @existing_keys ||= begin
          keys = []
          prefix = CloudfrontAssetHost.key_prefix
          prefix = "#{CloudfrontAssetHost.plain_prefix}/#{prefix}" if CloudfrontAssetHost.plain_prefix.present?
          keys.concat bucket.keys('prefix' => prefix).map { |key| key.name }
          keys.concat bucket.keys('prefix' => CloudfrontAssetHost.gzip_prefix).map { |key| key.name }
          keys
        end
      end

      def current_paths
        @current_paths ||= Dir.glob("#{Rails.public_path}/{#{asset_dirs.join(',')}}/**/*").reject { |path| File.directory?(path) }
      end

      def headers_for_path(extension, gzip = false)
        mime = ext_to_mime[extension] || 'application/octet-stream'
        headers = {
          'Content-Type' => mime,
          'Cache-Control' => "max-age=#{10.years.to_i}",
          'Expires' => 1.year.from_now.utc.to_s
        }
        headers['Content-Encoding'] = 'gzip' if gzip

        headers
      end

      def ext_to_mime
        @ext_to_mime ||= Hash[ *( YAML::load_file(File.join(File.dirname(__FILE__), "mime_types.yml")).collect { |k,vv| vv.collect{ |v| [v,k] } }.flatten ) ]
      end

      def bucket
        @bucket ||= begin
          bucket = s3.bucket(CloudfrontAssetHost.bucket)
          bucket.disable_logging unless CloudfrontAssetHost.s3_logging
          bucket
        end
      end

      def s3
        @s3 ||= RightAws::S3.new(config['access_key_id'], config['secret_access_key'])
      end

      def config
        @config ||= begin
          config = YAML::load_file(CloudfrontAssetHost.s3_config)
          config.has_key?(Rails.env) ? config[Rails.env] : config
        end
      end

      def asset_dirs
        @asset_dirs ||= CloudfrontAssetHost.asset_dirs
      end

    end

  end
end
Something went wrong with that request. Please try again.