lib/lobber/uploader.rb

Summary

Maintainability
A
35 mins
Test Coverage
require 'fog'
require 'rake'

module Lobber
  class Uploader
    attr_reader :directory, :bucket_name, :dry_run, :verbose

    def initialize(directory, options = {})
      @directory = sanitize(directory)

      @bucket_name = options.fetch('bucket', nil)
      @dry_run = options.fetch('dry_run', false)
      @verbose = options.fetch('verbose', true)
    end

    def upload
      verify_env_variables
      directory_content.each do |file, value|
        create_file_or_directory(file, value)
      end
    end

    def directory_content
      hash = {}

      Rake::FileList["#{directory}/**/*"].each do |path|
        if File.directory?(path)
          hash["#{path}/"] = :directory
        else
          hash[path] = File.read(path)
        end
      end

      hash
    end

    def bucket
      @bucket ||= s3.directories.create(key: fog_directory, public: true)
    end

    def create_file_or_directory(file_or_directory, directory_flag)
      if directory_flag == :directory
        create_directory file_or_directory
      else
        create_file file_or_directory
      end
    end

    def create_directory directory
      return if dry_run
      bucket.files.create(key: directory, public: true)
    end

    def create_file file
      key = Pathname.new(file).relative_path_from(Pathname.new(directory)).to_s

      if already_identical?(file, key)
        log "#{file} identical"
        return
      end

      log file, key
      return if dry_run
      bucket.files.create(key: key, public: true, body: File.open(file))
    end

    def s3
      @s3 ||= Fog::Storage.new(
        provider: :aws,
        aws_access_key_id: aws_access_key,
        aws_secret_access_key: aws_secret_key,
        path_style: fog_directory.include?(?.)
      )
    end

    def verify_env_variables
      missing = []

      missing << 'AWS_ACCESS_KEY' unless aws_access_key
      missing << 'AWS_SECRET_KEY' unless aws_secret_key
      missing << 'FOG_DIRECTORY' unless fog_directory

      return true if missing.empty?

      raise "Required environment variables missing: #{missing.inspect}"
    end

    def aws_access_key
      ENV['AWS_ACCESS_KEY']
    end

    def aws_secret_key
      ENV['AWS_SECRET_KEY']
    end

    def fog_directory
      bucket_name || ENV['FOG_DIRECTORY']
    end

    private

    def already_identical?(file, key)
      remote_file = bucket.files.head(key)
      remote_file && Digest::MD5.hexdigest(File.read(file)) == remote_file.etag
    end

    def log(*strings)
      puts strings.join(' -> ') if verbose
    end

    def sanitize(directory_path)
      if directory_path.match(/\/$/)
        directory_path.chop
      else
        directory_path
      end
    end
  end
end