require 'pathname' require_relative 'slug/bucket' require_relative 'repo' require_relative 'shellable' module Hillary class Slug include Shellable attr_reader :branch, :version SlugArchiveError = Class.new(StandardError) SlugNotFoundError = Class.new(StandardError) class << self def build(path = File.expand_path('.'), version = Repo::Version.create!, options = {}) return unless version.sluggable? new(path, version, options).tap{|slug| slug.build} end end def initialize(path, version, options = {}) @path = path @version = version @bucket = options[:bucket] || Bucket.new @logger = if options[:logger] options[:logger] else Logger.new($stdout).tap do |logger| logger.formatter = proc do |severity, time, _, msg| "#{time.strftime('%Y-%m-%d %H:%M:%S')} #{severity} - #{msg}\n" end end end end def build if version.master? create_slug_if_missing copy_slug elsif version.dev? create_slug upload_slug end end def name "#{project_name}_slug_#{version.name}" end def canonical_name "#{project_name}_slug_#{version.sha}" end private attr_reader :logger, :bucket, :path def create_slug_if_missing return if bucket.exists?(canonical_storage_slug_file) if version.production? raise SlugNotFoundError, "Attempted to create production slug from RC, but canonical slug (#{bucket.name}:/#{canonical_storage_slug_file}) couldn't be found" else logger.warn("Unable to find slug #{bucket.name}:/#{canonical_storage_slug_file}") create_slug upload_slug end end def copy_slug logger.info("Copying #{bucket.name}:/#{canonical_storage_slug_file} to #{bucket.name}:/#{storage_slug_file}") bucket.copy(canonical_storage_slug_file, storage_slug_file) end def create_slug Dir.chdir(project_parent_directory) do logger.info("Creating slug #{canonical_slug_file}") command = "tar --exclude \".git\" --exclude \"vendor/bundle\" -zcvf #{canonical_slug_file} #{project_name}" shell(command, logger: logger) end end def upload_slug logger.info("Uploading #{canonical_slug_file} to #{bucket.name}:/#{canonical_storage_slug_file}") bucket.write(canonical_storage_slug_file, project_parent_directory.join(canonical_slug_file)) end def slug_file "#{name}.tar.gz" end def storage_slug_file if version.master? if version.production? "production/#{slug_file}" else "rc/#{slug_file}" end elsif version.dev? "dev/#{slug_file}" end end def canonical_slug_file "#{canonical_name}.tar.gz" end def canonical_storage_slug_file "dev/#{canonical_slug_file}" end def project_directory Pathname.new(path).expand_path end def project_parent_directory project_directory.join('..').expand_path end def project_name project_directory.basename.to_s end end end