class S3Deployer
Constants
- CURRENT_REVISION
- DATE_FORMAT
- RETRY_TIMES
- VERSION
Attributes
config[R]
Public Class Methods
changes(from, to)
click to toggle source
# File lib/s3_deployer.rb, line 116 def changes(from, to) from_sha = sha_of_revision(from) to_sha = sha_of_revision(to) if from_sha && to_sha `git log --oneline --reverse #{from_sha}...#{to_sha}`.split("\n").map(&:strip) else [] end end
configure(&block)
click to toggle source
# File lib/s3_deployer.rb, line 24 def configure(&block) @config = Config.new @config.instance_eval(&block) @config.apply_environment_settings! Aws.config.update({ region: config.region, credentials: Aws::Credentials.new(config.access_key_id, config.secret_access_key, config.session_token), }) end
current()
click to toggle source
# File lib/s3_deployer.rb, line 84 def current current_revision = get_current_revision if current_revision puts "Current revision: #{current_revision} - #{get_datetime_from_revision(current_revision)}" else puts "There is no information about the current revision" end end
deploy!()
click to toggle source
# File lib/s3_deployer.rb, line 40 def deploy! revision = config.revision || time_zone.now.strftime(DATE_FORMAT) config.before_deploy[revision] if config.before_deploy stage!(revision) switch!(revision) config.after_deploy[revision] if config.after_deploy end
execute(cmd)
click to toggle source
# File lib/s3_deployer.rb, line 35 def execute(cmd) puts "Running '#{cmd}'" system(cmd, out: $stdout, err: :out) end
list()
click to toggle source
# File lib/s3_deployer.rb, line 104 def list puts "Getting the list of deployed revisions..." current_revision = get_current_revision get_list_of_revisions.each do |rev| datetime = get_datetime_from_revision(rev) sha = shas_by_revisions[rev] title = sha ? `git show -s --format=%s #{sha}`.strip : nil string = "#{rev} - #{datetime} #{sha ? " - #{sha[0..7]}" : ""} #{title ? "(#{title})" : ""} #{" <= current" if rev == current_revision}" puts string end end
normalize_revision(revision)
click to toggle source
# File lib/s3_deployer.rb, line 93 def normalize_revision(revision) if revision && !revision.empty? datetime = get_datetime_from_revision(revision) if datetime revision else shas_by_revisions.detect { |k, v| v.start_with?(revision) }.first end end end
sha_of_revision(revision)
click to toggle source
# File lib/s3_deployer.rb, line 126 def sha_of_revision(revision) shas_by_revisions[revision] end
stage!(revision = (config.revision || time_zone.now.strftime(DATE_FORMAT)))
click to toggle source
# File lib/s3_deployer.rb, line 48 def stage!(revision = (config.revision || time_zone.now.strftime(DATE_FORMAT))) puts "Staging #{colorize(:green, revision)}" config.before_stage[revision] if config.before_stage copy_files_to_s3(revision) store_git_hash(revision) config.after_stage[revision] if config.after_stage end
switch!(revision = config.revision)
click to toggle source
# File lib/s3_deployer.rb, line 56 def switch!(revision = config.revision) current_revision = get_current_revision current_sha = sha_of_revision(current_revision) sha = sha_of_revision(revision) puts "Switching from #{colorize(:green, current_revision)} (#{colorize(:yellow, current_sha && current_sha[0..7])}) " + "to #{colorize(:green, revision)} (#{colorize(:yellow, sha && sha[0..7])})" if !revision || revision.strip.empty? warn "You must specify the revision by REVISION env variable" exit(1) end config.before_switch[current_revision, revision] if config.before_switch prefix = config.app_path.empty? ? revision : File.join(revisions_path, revision) list_of_objects = [] Aws::S3::Resource.new.bucket(config.bucket).objects(prefix: prefix).each do |object_summary| list_of_objects << object_summary end Parallel.each(list_of_objects, in_threads: 20) do |object_summary| object = object_summary.object target_path = config.app_path.empty? ? @config.current_path : File.join(config.app_path, @config.current_path) path = object.key.gsub(prefix, target_path) value = object.get.body.read value = object.content_encoding == "gzip" ? decompress(value) : value store_value(path, value) end store_current_revision(revision) config.after_switch[current_revision, revision] if config.after_switch end
Private Class Methods
app_path_with_bucket()
click to toggle source
# File lib/s3_deployer.rb, line 146 def app_path_with_bucket File.join(config.bucket, config.app_path) end
colorize(color, text)
click to toggle source
# File lib/s3_deployer.rb, line 261 def colorize(color, text) config.colorize ? Color.send(color, text) : text end
compress(source)
click to toggle source
# File lib/s3_deployer.rb, line 241 def compress(source) output = Stream.new gz = Zlib::GzipWriter.new(output, Zlib::DEFAULT_COMPRESSION, Zlib::DEFAULT_STRATEGY) gz.write(source) gz.close output.string end
copy_files_to_s3(rev)
click to toggle source
# File lib/s3_deployer.rb, line 132 def copy_files_to_s3(rev) dir = File.join(revisions_path, rev) Parallel.each(source_files_list, in_threads: 20) do |file| s3_file = Pathname.new(file).relative_path_from(Pathname.new(config.dist_dir)).to_s store_value(File.join(dir, s3_file), File.read(file)) end end
current_revision_path()
click to toggle source
# File lib/s3_deployer.rb, line 165 def current_revision_path File.join(config.app_path, CURRENT_REVISION) end
decompress(source)
click to toggle source
# File lib/s3_deployer.rb, line 249 def decompress(source) begin Zlib::GzipReader.new(StringIO.new(source)).read rescue Zlib::GzipFile::Error source end end
get_current_revision()
click to toggle source
# File lib/s3_deployer.rb, line 192 def get_current_revision get_value(current_revision_path) rescue Aws::S3::Errors::NoSuchKey nil end
get_datetime_from_revision(revision)
click to toggle source
# File lib/s3_deployer.rb, line 150 def get_datetime_from_revision(revision) date = Time.strptime(revision, DATE_FORMAT) rescue nil date.strftime("%m/%d/%Y %H:%M") if date end
get_list_of_revisions()
click to toggle source
# File lib/s3_deployer.rb, line 140 def get_list_of_revisions prefix = revisions_path body = Aws::S3::Client.new.list_objects({bucket: config.bucket, delimiter: '/', prefix: prefix + "/"}) body.common_prefixes.map(&:prefix).map { |e| e.gsub(prefix, "").gsub("/", "") }.sort end
get_value(key)
click to toggle source
# File lib/s3_deployer.rb, line 173 def get_value(key) puts "Retrieving value #{key} on S3" retry_block(RETRY_TIMES.dup) do Aws::S3::Resource.new.bucket(config.bucket).object(key).get.body.read end end
retry_block(sleep_times, &block)
click to toggle source
# File lib/s3_deployer.rb, line 215 def retry_block(sleep_times, &block) block.call rescue Exception => e puts "#{colorize(:red, "Error!")} #{e}\n\n#{e.backtrace.take(3).join("\n")}" no_retry_exceptions = [Aws::S3::Errors::NoSuchKey] if no_retry_exceptions.any? { |exc| e.is_a?(exc) } raise e elsif !sleep_times.empty? sleep_time = sleep_times.shift puts "Still have #{colorize(:yellow, "#{sleep_times.count} retries")}, so waiting for #{colorize(:yellow, "#{sleep_time} seconds")} and retrying..." sleep sleep_time retry_block(sleep_times, &block) else puts "Out of retries, failing..." raise e end end
revisions_path()
click to toggle source
# File lib/s3_deployer.rb, line 169 def revisions_path File.join(config.app_path, "revisions") end
shas_by_revisions()
click to toggle source
# File lib/s3_deployer.rb, line 155 def shas_by_revisions @shas_by_revisions ||= get_value(File.join(config.app_path, "SHAS")).split("\n").inject({}) do |memo, line| revision, sha = line.split(" - ").map(&:strip) memo[revision] = sha memo end rescue Aws::S3::Errors::NoSuchKey {} end
should_compress?(key)
click to toggle source
# File lib/s3_deployer.rb, line 233 def should_compress?(key) if [true, false, nil].include?(config.gzip) !!config.gzip else key != CURRENT_REVISION && Array(config.gzip).any? { |regexp| key.match(regexp) } end end
source_files_list()
click to toggle source
# File lib/s3_deployer.rb, line 257 def source_files_list Dir.glob(File.join(config.dist_dir, "**/*")).select { |f| File.file?(f) } end
store_current_revision(revision)
click to toggle source
# File lib/s3_deployer.rb, line 180 def store_current_revision(revision) store_value(current_revision_path, revision, cache_control: "max-age=0, no-cache") end
store_git_hash(time)
click to toggle source
# File lib/s3_deployer.rb, line 184 def store_git_hash(time) value = shas_by_revisions. merge(time => `git rev-parse HEAD`.strip). map { |sha, rev| "#{sha} - #{rev}" }.join("\n") store_value(File.join(config.app_path, "SHAS"), value, cache_control: "max-age=0, no-cache") @shas_by_revisions = nil end
store_value(key, value, options = {})
click to toggle source
# File lib/s3_deployer.rb, line 198 def store_value(key, value, options = {}) options = {acl: "public-read"}.merge(options) if config.cache_control && !config.cache_control.empty? options[:cache_control] = config.cache_control end if should_compress?(key) options[:content_encoding] = "gzip" value = compress(value) end mime_type = MIME::Types.of(key).first options[:content_type] = mime_type ? mime_type.content_type : "binary/octet-stream" retry_block(RETRY_TIMES.dup) do puts "Storing value #{colorize(:yellow, key)} on S3#{", #{colorize(:green, 'gzipped')}" if should_compress?(key)}" Aws::S3::Resource.new.bucket(config.bucket).object(key).put(options.merge(body: value)) end end
time_zone()
click to toggle source
# File lib/s3_deployer.rb, line 265 def time_zone TZInfo::Timezone.get(config.time_zone) end