#!/usr/bin/env ruby

require 'aws-sdk-s3'
require 'digest/md5'
require 'rack/mime'
require 'pathname'

CLIENT = Aws::S3::Client.new(region: ENV['AWS_REGION'] || 'eu-west-1')
BUCKET = File.basename(Dir.pwd)

USAGE = <<EOF
usage: #{$0} file...

the following environment vars will be used:

  AWS_REGION
  AWS_ACCESS_KEY_ID
  AWS_SECRET_ACCESS_KEY

EOF

def upload(files=["."])
  base = Pathname::new(files.first)
  files = files.map do |f|
    File.directory?(f) ? traverse(Dir.new(f)) : f
  end.flatten

  files.each do |f|
    print "#{f}.. "

    key = Pathname::new(f).relative_path_from(base).to_s
    mime = Rack::Mime::MIME_TYPES[File.extname(f)]
    cache = if /^text/.match?(mime) then 60 else 3600 end

    obj = CLIENT.get_object({bucket: BUCKET, key: key}) rescue nil
    local_md5 = md5sum(f).chomp
    remote_md5 = obj.etag.tr('"', '') if obj

    if local_md5.to_s != remote_md5.to_s
      CLIENT.put_object(
        body: File::new(f),
        key: key,
        bucket: BUCKET,
        content_type: mime,
        cache_control: "max-age=#{cache}",
        acl: "public-read"
      )

      puts "ok"
    else
      puts "skipping"
    end
  end
end

def md5sum(file_name)
  Digest::MD5.hexdigest(File.read(file_name))
end

def traverse(dir)
  list = []
  dir.each do |entry|
    unless [".", "..", ".git"].include?(entry)
      path = File.join(dir.path, entry)
      if File.directory?(path)
        list += traverse(Dir.new(path))
      else
        list << path
      end
    end
  end
  list
end

if ARGV[0] == "-h"
  puts USAGE
  exit 0
end

begin
  upload(ARGV)
rescue Exception => e
  $stderr.puts "error: #{e.message}"
  exit 1
end
