class Nanoc::Deploying::Deployers::Fog

A deployer that deploys a site using [fog](github.com/fog/fog).

@example A deployment configuration with public and staging configurations

deploy:
  public:
    kind:       fog
    bucket:     nanoc-site
    cdn_id:     XXXXXX
  preprod:
    kind:       fog
    provider:   local
    local_root: ~/myCloud
    bucket:     nanoc-site
  staging:
    kind:       fog
    provider:   local
    local_root: ~/myCloud
    bucket:     nanoc-site-staging

@api private

Public Instance Methods

run() click to toggle source

@see Nanoc::Deploying::Deployer#run

# File lib/nanoc/deploying/deployers/fog.rb, line 86
def run
  require 'fog/core'

  src      = File.expand_path(source_path)
  bucket   = config[:bucket] || config[:bucket_name]
  path     = config[:path]
  cdn_id   = config[:cdn_id]

  if path&.end_with?('/')
    raise "The path `#{path}` is not supposed to have a trailing slash"
  end

  connection = connect
  directory = get_or_create_bucket(connection, bucket, path)
  wrapper = FogWrapper.new(directory, dry_run?)

  remote_files = list_remote_files(directory)
  etags = read_etags(remote_files)

  modified_keys, retained_keys = upload_all(src, path, etags, wrapper)

  removed_keys = remote_files.map(&:key) - retained_keys - modified_keys
  wrapper.remove(removed_keys)

  if cdn_id
    cdn = ::Fog::CDN.new(config_for_fog)
    distribution = cdn.get_distribution(cdn_id)
    wrapper.invalidate(modified_keys + removed_keys, cdn, distribution)
  end
end

Private Instance Methods

calc_local_etag(file_path) click to toggle source
# File lib/nanoc/deploying/deployers/fog.rb, line 215
def calc_local_etag(file_path)
  case config[:provider]
  when 'aws'
    Digest::MD5.file(file_path).hexdigest
  end
end
config_for_fog() click to toggle source
# File lib/nanoc/deploying/deployers/fog.rb, line 119
def config_for_fog
  config.dup.tap do |c|
    c.delete(:bucket)
    c.delete(:bucket_name)
    c.delete(:path)
    c.delete(:cdn_id)
    c.delete(:kind)
  end
end
connect() click to toggle source
# File lib/nanoc/deploying/deployers/fog.rb, line 129
def connect
  ::Fog::Storage.new(config_for_fog)
rescue ArgumentError
  require "fog/#{config[:provider]}"
  ::Fog::Storage.new(config_for_fog)
end
get_or_create_bucket(connection, bucket, path) click to toggle source
# File lib/nanoc/deploying/deployers/fog.rb, line 136
def get_or_create_bucket(connection, bucket, path)
  directory =
    begin
      connection.directories.get(bucket, prefix: path)
    rescue ::Excon::Errors::NotFound
      nil
    end

  if directory
    directory
  elsif dry_run?
    puts '[dry run] creating bucket'
  else
    puts 'creating bucket'
    connection.directories.create(key: bucket, prefix: path)
  end
end
list_local_files(src) click to toggle source
# File lib/nanoc/deploying/deployers/fog.rb, line 174
def list_local_files(src)
  Dir[src + '/**/*'].select { |f| File.file?(f) }
end
list_remote_files(directory) click to toggle source
# File lib/nanoc/deploying/deployers/fog.rb, line 164
def list_remote_files(directory)
  if directory
    [].tap do |files|
      directory.files.each { |file| files << file }
    end
  else
    []
  end
end
needs_upload?(key, file_path, etags) click to toggle source
# File lib/nanoc/deploying/deployers/fog.rb, line 196
def needs_upload?(key, file_path, etags)
  remote_etag = etags[key]
  return true if remote_etag.nil?

  local_etag = calc_local_etag(file_path)
  remote_etag != local_etag
end
read_etags(files) click to toggle source
# File lib/nanoc/deploying/deployers/fog.rb, line 204
def read_etags(files)
  case config[:provider]
  when 'aws'
    files.each_with_object({}) do |file, etags|
      etags[file.key] = file.etag
    end
  else
    {}
  end
end
remote_key_for_local_filename(local_filename, src, path) click to toggle source
# File lib/nanoc/deploying/deployers/fog.rb, line 154
def remote_key_for_local_filename(local_filename, src, path)
  relative_local_filename = local_filename.sub(/\A#{src}\//, '')

  if path
    File.join(path, relative_local_filename)
  else
    relative_local_filename
  end
end
upload_all(src, path, etags, wrapper) click to toggle source
# File lib/nanoc/deploying/deployers/fog.rb, line 178
def upload_all(src, path, etags, wrapper)
  modified_keys = []
  retained_keys = []

  local_files = list_local_files(src)
  local_files.each do |file_path|
    key = remote_key_for_local_filename(file_path, src, path)
    if needs_upload?(key, file_path, etags)
      wrapper.upload(file_path, key)
      modified_keys.push(key)
    else
      retained_keys.push(key)
    end
  end

  [modified_keys, retained_keys]
end