class AssetSync::Storage
Constants
- REGEXP_ASSETS_TO_CACHE_CONTROL
- REGEXP_FINGERPRINTED_FILES
Attributes
config[RW]
Public Class Methods
new(cfg)
click to toggle source
# File lib/asset_sync/storage.rb, line 15 def initialize(cfg) @config = cfg end
Public Instance Methods
always_upload_files()
click to toggle source
# File lib/asset_sync/storage.rb, line 61 def always_upload_files expand_file_names(self.config.always_upload) + get_manifest_path end
bucket()
click to toggle source
# File lib/asset_sync/storage.rb, line 23 def bucket # fixes: https://github.com/rumblelabs/asset_sync/issues/18 @bucket ||= connection.directories.get(self.config.fog_directory, :prefix => self.config.assets_prefix) end
connection()
click to toggle source
# File lib/asset_sync/storage.rb, line 19 def connection @connection ||= Fog::Storage.new(self.config.fog_options) end
delete_extra_remote_files()
click to toggle source
# File lib/asset_sync/storage.rb, line 128 def delete_extra_remote_files log "Fetching files to flag for delete" remote_files = get_remote_files # fixes: https://github.com/rumblelabs/asset_sync/issues/19 from_remote_files_to_delete = remote_files - local_files - ignored_files - always_upload_files log "Flagging #{from_remote_files_to_delete.size} file(s) for deletion" # Delete unneeded remote files bucket.files.each do |f| delete_file(f, from_remote_files_to_delete) end end
delete_file(f, remote_files_to_delete)
click to toggle source
# File lib/asset_sync/storage.rb, line 121 def delete_file(f, remote_files_to_delete) if remote_files_to_delete.include?(f.key) log "Deleting: #{f.key}" f.destroy end end
files_to_invalidate()
click to toggle source
# File lib/asset_sync/storage.rb, line 69 def files_to_invalidate self.config.invalidate.map { |filename| File.join("/", self.config.assets_prefix, filename) } end
files_with_custom_headers()
click to toggle source
# File lib/asset_sync/storage.rb, line 65 def files_with_custom_headers self.config.custom_headers.inject({}) { |h,(k, v)| h[File.join(self.config.assets_prefix, k)] = v; h; } end
get_asset_files_from_manifest()
click to toggle source
@api
To get a list of asset files indicated in a manifest file. It makes sense if a user sets `config.manifest` is true.
# File lib/asset_sync/storage.rb, line 76 def get_asset_files_from_manifest if self.config.manifest if ActionView::Base.respond_to?(:assets_manifest) log "Using: Rails 4.0 manifest access" manifest = Sprockets::Manifest.new(ActionView::Base.assets_manifest.environment, ActionView::Base.assets_manifest.dir) return manifest.assets.values.map { |f| File.join(self.config.assets_prefix, f) } elsif File.exist?(self.config.manifest_path) log "Using: Manifest #{self.config.manifest_path}" yml = YAML.load(IO.read(self.config.manifest_path)) return yml.map do |original, compiled| # Upload font originals and compiled if original =~ /^.+(eot|svg|ttf|woff)$/ [original, compiled] else compiled end end.flatten.map { |f| File.join(self.config.assets_prefix, f) }.uniq! else log "Warning: Manifest could not be found" end end end
get_local_files()
click to toggle source
# File lib/asset_sync/storage.rb, line 100 def get_local_files if from_manifest = get_asset_files_from_manifest return from_manifest end log "Using: Directory Search of #{path}/#{self.config.assets_prefix}" Dir.chdir(path) do to_load = self.config.assets_prefix.present? ? "#{self.config.assets_prefix}/**/**" : '**/**' Dir[to_load] end end
get_manifest_path()
click to toggle source
# File lib/asset_sync/storage.rb, line 44 def get_manifest_path return [] unless self.config.include_manifest if ActionView::Base.respond_to?(:assets_manifest) manifest = Sprockets::Manifest.new(ActionView::Base.assets_manifest.environment, ActionView::Base.assets_manifest.dir) manifest_path = manifest.filename else manifest_path = self.config.manifest_path end [manifest_path.sub(/^#{path}\//, "")] # full path to relative path end
get_remote_files()
click to toggle source
# File lib/asset_sync/storage.rb, line 112 def get_remote_files raise BucketNotFound.new("#{self.config.fog_provider} Bucket: #{self.config.fog_directory} not found.") unless bucket # fixes: https://github.com/rumblelabs/asset_sync/issues/16 # (work-around for https://github.com/fog/fog/issues/596) files = [] bucket.files.each { |f| files << f.key } return files end
ignored_files()
click to toggle source
# File lib/asset_sync/storage.rb, line 40 def ignored_files expand_file_names(self.config.ignored_files) end
keep_existing_remote_files?()
click to toggle source
# File lib/asset_sync/storage.rb, line 32 def keep_existing_remote_files? self.config.existing_remote_files? end
local_files()
click to toggle source
# File lib/asset_sync/storage.rb, line 56 def local_files @local_files ||= (get_local_files + config.additional_local_file_paths).uniq end
log(msg)
click to toggle source
# File lib/asset_sync/storage.rb, line 28 def log(msg) AssetSync.log(msg) end
path()
click to toggle source
# File lib/asset_sync/storage.rb, line 36 def path self.config.public_path end
sync()
click to toggle source
# File lib/asset_sync/storage.rb, line 259 def sync # fixes: https://github.com/rumblelabs/asset_sync/issues/19 log "AssetSync: Syncing." upload_files delete_extra_remote_files unless keep_existing_remote_files? log "AssetSync: Done." end
upload_file(f)
click to toggle source
# File lib/asset_sync/storage.rb, line 141 def upload_file(f) # TODO output files in debug logs as asset filename only. one_year = 31557600 ext = File.extname(f)[1..-1] mime = MultiMime.lookup(ext) gzip_file_handle = nil file_handle = File.open("#{path}/#{f}") file = { :key => f, :body => file_handle, :public => true, :content_type => mime } uncompressed_filename = f.sub(/\.gz\z/, '') basename = File.basename(uncompressed_filename, File.extname(uncompressed_filename)) assets_to_cache_control = Regexp.union([REGEXP_ASSETS_TO_CACHE_CONTROL] | config.cache_asset_regexps).source if basename.match(Regexp.new(assets_to_cache_control)).present? file.merge!({ :cache_control => "public, max-age=#{one_year}", :expires => CGI.rfc1123_date(Time.now + one_year) }) end # overwrite headers if applicable, you probably shouldn't specific key/body, but cache-control headers etc. if files_with_custom_headers.has_key? f file.merge! files_with_custom_headers[f] log "Overwriting #{f} with custom headers #{files_with_custom_headers[f].to_s}" elsif key = self.config.custom_headers.keys.detect {|k| f.match(Regexp.new(k))} headers = {} self.config.custom_headers[key].each do |k, value| headers[k.to_sym] = value end file.merge! headers log "Overwriting matching file #{f} with custom headers #{headers.to_s}" end 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. log "Ignoring: #{f}" ignore = true elsif config.gzip? && File.exist?(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) gzip_file_handle = File.open(gzipped) file.merge!({ :key => f, :body => gzip_file_handle, :content_encoding => 'gzip' }) log "Uploading: #{gzipped} in place of #{f} saving #{percentage}%" else percentage = ((original_size.to_f/gzipped_size.to_f)*100).round(2) log "Uploading: #{f} instead of #{gzipped} (compression increases this file by #{percentage}%)" end else if !config.gzip? && File.extname(f) == ".gz" # set content encoding for gzipped files this allows cloudfront to properly handle requests with Accept-Encoding # http://docs.amazonwebservices.com/AmazonCloudFront/latest/DeveloperGuide/ServingCompressedFiles.html uncompressed_filename = f[0..-4] ext = File.extname(uncompressed_filename)[1..-1] mime = MultiMime.lookup(ext) file.merge!({ :content_type => mime, :content_encoding => 'gzip' }) end log "Uploading: #{f}" end if config.aws? && config.aws_rrs? file.merge!({ :storage_class => 'REDUCED_REDUNDANCY' }) end if config.azure_rm? # converts content_type from MIME::Type to String. # because Azure::Storage (called from Fog::AzureRM) expects content_type as a String like "application/json; charset=utf-8" file[:content_type] = file[:content_type].content_type if file[:content_type].is_a?(::MIME::Type) end bucket.files.create( file ) unless ignore file_handle.close gzip_file_handle.close if gzip_file_handle end
upload_files()
click to toggle source
# File lib/asset_sync/storage.rb, line 238 def upload_files # get a fresh list of remote files remote_files = ignore_existing_remote_files? ? [] : get_remote_files # fixes: https://github.com/rumblelabs/asset_sync/issues/19 local_files_to_upload = local_files - ignored_files - remote_files + always_upload_files local_files_to_upload = (local_files_to_upload + get_non_fingerprinted(local_files_to_upload)).uniq # Upload new files local_files_to_upload.each do |f| next unless File.file? "#{path}/#{f}" # Only files. upload_file f end if self.config.cdn_distribution_id && files_to_invalidate.any? log "Invalidating Files" cdn ||= Fog::CDN.new(self.config.fog_options.except(:region)) data = cdn.post_invalidation(self.config.cdn_distribution_id, files_to_invalidate) log "Invalidation id: #{data.body["Id"]}" end end
Private Instance Methods
expand_file_names(names)
click to toggle source
# File lib/asset_sync/storage.rb, line 280 def expand_file_names(names) files = [] Array(names).each do |name| case name when Regexp files += self.local_files.select do |file| file =~ name end when String files += self.local_files.select do |file| file.split('/').last == name end else log "Error: please define file names as string or regular expression. #{name} (#{name.class}) ignored." end end files.uniq end
get_non_fingerprinted(files)
click to toggle source
# File lib/asset_sync/storage.rb, line 273 def get_non_fingerprinted(files) files.map do |file| match_data = file.match(REGEXP_FINGERPRINTED_FILES) match_data && "#{match_data[1]}/#{match_data[2]}.#{match_data[3]}" end.compact end
ignore_existing_remote_files?()
click to toggle source
# File lib/asset_sync/storage.rb, line 269 def ignore_existing_remote_files? self.config.existing_remote_files == 'ignore' end