module Capistrano::S3::Publisher
Constants
- LAST_INVALIDATION_FILE
- LAST_PUBLISHED_FILE
Public Class Methods
check_invalidation(region, key, secret, distribution_id, stage = 'default')
click to toggle source
# File lib/capistrano/s3/publisher.rb, line 62 def self.check_invalidation(region, key, secret, distribution_id, stage = 'default') last_invalidation_id = File.read(LAST_INVALIDATION_FILE).strip cf = self.establish_cf_client_connection!(region, key, secret) cf.wait_until(:invalidation_completed, distribution_id: distribution_id, id: last_invalidation_id) do |w| w.max_attempts = nil w.delay = 30 end end
clear!(region, key, secret, bucket, stage = 'default')
click to toggle source
# File lib/capistrano/s3/publisher.rb, line 54 def self.clear!(region, key, secret, bucket, stage = 'default') s3 = self.establish_s3_connection!(region, key, secret) s3.buckets[bucket].clear! self.clear_published!(bucket, stage) FileUtils.rm(LAST_INVALIDATION_FILE) end
publish!(region, key, secret, bucket, deployment_path, target_path, distribution_id, invalidations, exclusions, only_gzip, extra_options, stage = 'default')
click to toggle source
# File lib/capistrano/s3/publisher.rb, line 12 def self.publish!(region, key, secret, bucket, deployment_path, target_path, distribution_id, invalidations, exclusions, only_gzip, extra_options, stage = 'default') deployment_path_absolute = File.expand_path(deployment_path, Dir.pwd) s3 = self.establish_s3_client_connection!(region, key, secret) updated = false self.files(deployment_path_absolute, exclusions).each do |file| if !File.directory?(file) next if self.published?(file, bucket, stage) next if only_gzip && self.has_gzipped_version?(file) path = self.base_file_path(deployment_path_absolute, file) path.gsub!(/^\//, "") # Remove preceding slash for S3 self.put_object(s3, bucket, target_path, path, file, only_gzip, extra_options) end end # invalidate CloudFront distribution if needed if distribution_id && !invalidations.empty? cf = self.establish_cf_client_connection!(region, key, secret) response = cf.create_invalidation({ :distribution_id => distribution_id, :invalidation_batch => { :paths => { :quantity => invalidations.count, :items => invalidations.map do |path| File.join('/', self.add_prefix(path, prefix: target_path)) end }, :caller_reference => SecureRandom.hex } }) if response && response.successful? File.open(LAST_INVALIDATION_FILE, 'w') { |file| file.write(response[:invalidation][:id]) } end end self.published_to!(bucket, stage) end
Private Class Methods
add_prefix(path, prefix:)
click to toggle source
# File lib/capistrano/s3/publisher.rb, line 226 def self.add_prefix(path, prefix:) if prefix.empty? path else File.join(prefix, path) end end
base_file_path(root, file)
click to toggle source
# File lib/capistrano/s3/publisher.rb, line 98 def self.base_file_path(root, file) file.gsub(root, "") end
build_content_type_hash(mime_type)
click to toggle source
# File lib/capistrano/s3/publisher.rb, line 183 def self.build_content_type_hash(mime_type) { :content_type => mime_type.content_type } end
build_gzip_content_encoding_hash()
click to toggle source
# File lib/capistrano/s3/publisher.rb, line 187 def self.build_gzip_content_encoding_hash { :content_encoding => "gzip" } end
build_gzip_content_type_hash(file, mime_type, prefer_cf_mime_types)
click to toggle source
# File lib/capistrano/s3/publisher.rb, line 195 def self.build_gzip_content_type_hash(file, mime_type, prefer_cf_mime_types) orig_name = self.orig_name(file) orig_mime = mime_type_for_file(orig_name, prefer_cf_mime_types) return {} unless orig_mime && File.exist?(orig_name) { :content_type => orig_mime.content_type } end
build_redirect_hash(path, redirect_options)
click to toggle source
# File lib/capistrano/s3/publisher.rb, line 177 def self.build_redirect_hash(path, redirect_options) return {} unless redirect_options && redirect_options[path] { :website_redirect_location => redirect_options[path] } end
clear_published!(bucket, stage)
click to toggle source
# File lib/capistrano/s3/publisher.rb, line 129 def self.clear_published!(bucket, stage) current_publish = self.last_published current_publish["#{bucket}::#{stage}"] = nil File.write(LAST_PUBLISHED_FILE, current_publish.to_yaml) end
establish_cf_client_connection!(region, key, secret)
click to toggle source
# File lib/capistrano/s3/publisher.rb, line 86 def self.establish_cf_client_connection!(region, key, secret) self.establish_connection!(Aws::CloudFront::Client, region, key, secret) end
establish_connection!(klass, region, key, secret)
click to toggle source
Establishes the connection to Amazon S3
# File lib/capistrano/s3/publisher.rb, line 75 def self.establish_connection!(klass, region, key, secret) # Send logging to STDOUT Aws.config[:logger] = ::Logger.new(STDOUT) Aws.config[:log_formatter] = Aws::Log::Formatter.colored klass.new( :region => region, :access_key_id => key, :secret_access_key => secret ) end
establish_s3_client_connection!(region, key, secret)
click to toggle source
# File lib/capistrano/s3/publisher.rb, line 90 def self.establish_s3_client_connection!(region, key, secret) self.establish_connection!(Aws::S3::Client, region, key, secret) end
establish_s3_connection!(region, key, secret)
click to toggle source
# File lib/capistrano/s3/publisher.rb, line 94 def self.establish_s3_connection!(region, key, secret) self.establish_connection!(Aws::S3, region, key, secret) end
files(deployment_path, exclusions)
click to toggle source
# File lib/capistrano/s3/publisher.rb, line 102 def self.files(deployment_path, exclusions) globbed_paths = Dir.glob( File.join(deployment_path, '**', '*'), File::FNM_DOTMATCH # Else Unix-like hidden files will be ignored ) excluded_paths = Dir.glob( exclusions.map { |e| File.join(deployment_path, e) } ) globbed_paths - excluded_paths end
gzip_name(file)
click to toggle source
# File lib/capistrano/s3/publisher.rb, line 218 def self.gzip_name(file) "#{file}.gz" end
has_gzipped_version?(file)
click to toggle source
# File lib/capistrano/s3/publisher.rb, line 191 def self.has_gzipped_version?(file) File.exist?(self.gzip_name(file)) end
last_published()
click to toggle source
# File lib/capistrano/s3/publisher.rb, line 115 def self.last_published if File.exists? LAST_PUBLISHED_FILE YAML.load_file(LAST_PUBLISHED_FILE) || {} else {} end end
mime_type_for_file(file, prefer_cf_mime_types)
click to toggle source
# File lib/capistrano/s3/publisher.rb, line 204 def self.mime_type_for_file(file, prefer_cf_mime_types) types = MIME::Types.type_for(file) if prefer_cf_mime_types intersection = types & Capistrano::S3::MIMETypes::CF_MIME_TYPES unless intersection.empty? types = intersection end end types.first end
orig_name(file)
click to toggle source
# File lib/capistrano/s3/publisher.rb, line 222 def self.orig_name(file) file.sub(/\.gz$/, "") end
published?(file, bucket, stage)
click to toggle source
# File lib/capistrano/s3/publisher.rb, line 135 def self.published?(file, bucket, stage) return false unless last_publish_time = self.last_published["#{bucket}::#{stage}"] File.mtime(file) < Time.parse(last_publish_time) end
published_to!(bucket, stage)
click to toggle source
# File lib/capistrano/s3/publisher.rb, line 123 def self.published_to!(bucket, stage) current_publish = self.last_published current_publish["#{bucket}::#{stage}"] = Time.now.iso8601 File.write(LAST_PUBLISHED_FILE, current_publish.to_yaml) end
put_object(s3, bucket, target_path, path, file, only_gzip, extra_options)
click to toggle source
# File lib/capistrano/s3/publisher.rb, line 140 def self.put_object(s3, bucket, target_path, path, file, only_gzip, extra_options) prefer_cf_mime_types = extra_options[:prefer_cf_mime_types] || false base_name = File.basename(file) mime_type = mime_type_for_file(base_name, prefer_cf_mime_types) options = { :bucket => bucket, :key => self.add_prefix(path, prefix: target_path), :body => open(file), :acl => 'public-read', } options.merge!(build_redirect_hash(path, extra_options[:redirect])) options.merge!(extra_options[:write] || {}) object_write_options = extra_options[:object_write] || {} object_write_options.each do |pattern, object_options| if File.fnmatch(pattern, options[:key]) options.merge!(object_options) end end if mime_type options.merge!(build_content_type_hash(mime_type)) if mime_type.sub_type == "gzip" options.merge!(build_gzip_content_encoding_hash) options.merge!(build_gzip_content_type_hash(file, mime_type, prefer_cf_mime_types)) # upload as original file name options.merge!(key: self.add_prefix(self.orig_name(path), prefix: target_path)) if only_gzip end end s3.put_object(options) end