class Cloudinary::Static

Constants

DEFAULT_IMAGE_DIRS
DEFAULT_IMAGE_EXTENSION_MASK
IGNORE_FILES
METADATA_FILE
METADATA_TRASH_FILE

Public Class Methods

public_id_and_resource_type_from_path(path) click to toggle source

Cloudinary::Utils support ###

# File lib/cloudinary/static.rb, line 79
def public_id_and_resource_type_from_path(path)
  @metadata ||= build_metadata
  path = path.sub(/^\//, '')
  prefix = public_prefixes.find {|prefix| @metadata[File.join(prefix, path)]}
  if prefix
    [@metadata[File.join(prefix, path)]['public_id'], resource_type(path)]
  else
    nil
  end
end
sync(options={}) click to toggle source
# File lib/cloudinary/static.rb, line 12
def sync(options={})
  options = options.clone
  delete_missing = options.delete(:delete_missing)
  found_paths = Set.new
  found_public_paths = {}
  found_public_ids = Set.new
  metadata = build_metadata
  metadata_lines = []
  counts = { :not_changed => 0, :uploaded => 0, :deleted => 0, :not_found => 0}
  discover_all do |path, public_path|
    next if found_paths.include?(path)
    if found_public_paths[public_path]
      print "Warning: duplicate #{public_path} in #{path} - already taken from #{found_public_paths[public_path]}\n"
      next
    end
    found_paths << path
    found_public_paths[public_path] = path
    data = root.join(path).read(:mode=>"rb")
    ext = path.extname
    format = ext[1..-1]
    md5 = Digest::MD5.hexdigest(data)
    public_id = "#{public_path.basename(ext)}-#{md5}"
    found_public_ids << public_id
    item_metadata = metadata.delete(public_path.to_s)
    if item_metadata && item_metadata["public_id"] == public_id # Signature match
      counts[:not_changed] += 1
      print "#{public_path} - #{public_id} - Not changed\n"
      result = item_metadata
    else
      counts[:uploaded] += 1
      print "#{public_path} - #{public_id} - Uploading\n"
      result = Cloudinary::Uploader.upload(Cloudinary::Blob.new(data, :original_filename=>path.to_s),
        options.merge(:format=>format, :public_id=>public_id, :type=>:asset, :resource_type=>resource_type(path.to_s))
      ).merge("upload_time"=>Time.now)
    end
    metadata_lines << [public_path, public_id, result["upload_time"].to_i, result["version"], result["width"], result["height"]].join("\t")+"\n"
  end
  File.open(metadata_file_path, "w"){|f| f.print(metadata_lines.join)}
  metadata.to_a.each do |path, info|
    counts[:not_found] += 1
    print "#{path} - #{info["public_id"]} - Not found\n"      
  end
  # Files no longer needed
  trash = metadata.to_a + build_metadata(metadata_trash_file_path, false).reject{|public_path, info| found_public_ids.include?(info["public_id"])}
  
  if delete_missing
    trash.each do
      |path, info|
      counts[:deleted] += 1
      print "#{path} - #{info["public_id"]} - Deleting\n"
      Cloudinary::Uploader.destroy(info["public_id"], options.merge(:type=>:asset))
    end
    FileUtils.rm_f(metadata_trash_file_path)
  else
    # Add current removed file to the trash file.
    metadata_lines = trash.map do
      |public_path, info|
      [public_path, info["public_id"], info["upload_time"].to_i, info["version"], info["width"], info["height"]].join("\t")+"\n"
    end
    File.open(metadata_trash_file_path, "w"){|f| f.print(metadata_lines.join)}
  end
  
  print "\nCompleted syncing static resources to Cloudinary\n"
  print counts.sort.reject{|k,v| v == 0}.map{|k,v| "#{v} #{k.to_s.gsub('_', ' ').capitalize}"}.join(", ") + "\n"
end

Private Class Methods

absolutize(dirs) click to toggle source
# File lib/cloudinary/static.rb, line 217
def absolutize(dirs)
  dirs.map do |relative_dir|
    absolute_dir = root.join(relative_dir)
    if absolute_dir.exist?
      absolute_dir
    else
      print "Skipping #{relative_dir} (does not exist)\n"
      nil
    end
  end.compact
end
build_metadata(metadata_file = metadata_file_path, hash = true) click to toggle source
# File lib/cloudinary/static.rb, line 103
def build_metadata(metadata_file = metadata_file_path, hash = true)
  metadata = []
  if File.exist?(metadata_file)
    IO.foreach(metadata_file) do
    |line|
      line.strip!
      next if line.blank?
      path, public_id, upload_time, version, width, height = line.split("\t")
      metadata << [path, {
        "public_id" => public_id,
        "upload_time" => Time.at(upload_time.to_i).getutc,
        "version" => version,
        "width" => width.to_i,
        "height" => height.to_i
      }]
    end
  end
  hash ? Hash[*metadata.flatten] : metadata
end
discover(dirs, matcher) { |relative_path, public_path| ... } click to toggle source
# File lib/cloudinary/static.rb, line 131
def discover(dirs, matcher)
  return unless matcher

  dirs.each do |dir|
    print "Scanning #{dir.relative_path_from(root)}...\n"
    dir.find do |path|
      file = path.basename.to_s
      if ignore_file?(file)
        Find.prune
        next
      elsif path.directory? || !matcher.call(path.to_s)
        next
      else
        relative_path = path.relative_path_from(root)
        public_path = path.relative_path_from(dir.dirname)
        yield(relative_path, public_path)
      end
    end
  end
end
discover_all(&block) click to toggle source
# File lib/cloudinary/static.rb, line 123
def discover_all(&block)
  static_file_config.each do |group, data|
    print "-> Syncing #{group}...\n"
    discover(absolutize(data['dirs']), extension_matcher_for(group), &block)
    print "=========================\n"
  end
end
extension_mask_to_regex(extension_mask) click to toggle source
# File lib/cloudinary/static.rb, line 207
def extension_mask_to_regex(extension_mask)
  extension_mask && /\.(?:#{extension_mask})$/i
end
extension_matcher_for(group) click to toggle source
# File lib/cloudinary/static.rb, line 161
def extension_matcher_for(group)
  group = group.to_s
  return unless static_file_config[group]
  @matchers = {}
  @matchers[group] ||= ->(target) do
    !!target.match(extension_mask_to_regex(static_file_config[group]['file_mask']))
  end
end
ignore_file?(file) click to toggle source
# File lib/cloudinary/static.rb, line 152
def ignore_file?(file)
  matches?(file, Cloudinary.config.ignore_files || IGNORE_FILES)
end
image?(path) click to toggle source
# File lib/cloudinary/static.rb, line 195
def image?(path)
  extension_matcher_for(:images).call(path)
end
matches?(target, patterns) click to toggle source

Test for matching either strings or regexps

# File lib/cloudinary/static.rb, line 157
def matches?(target, patterns)
  Array(patterns).any? {|pattern| pattern.is_a?(String) ? pattern == target : target.match(pattern)}
end
metadata_file_path() click to toggle source
# File lib/cloudinary/static.rb, line 95
def metadata_file_path
  root.join(METADATA_FILE)
end
metadata_trash_file_path() click to toggle source
# File lib/cloudinary/static.rb, line 99
def metadata_trash_file_path
  root.join(METADATA_TRASH_FILE)
end
print(s) click to toggle source
public_prefixes() click to toggle source
# File lib/cloudinary/static.rb, line 211
def public_prefixes
  @public_prefixes ||= static_file_config.reduce([]) do |result, (group, data)|
    result << data['dirs'].map { |dir| Pathname.new(dir).basename.to_s }
  end.flatten.uniq
end
reset_static_file_config!() click to toggle source
# File lib/cloudinary/static.rb, line 191
def reset_static_file_config!
  @static_file_config = nil
end
resource_type(path) click to toggle source
# File lib/cloudinary/static.rb, line 199
def resource_type(path)
  if image?(path)
    :image
  else
    :raw
  end
end
root() click to toggle source
# File lib/cloudinary/static.rb, line 91
def root
  Cloudinary.app_root
end
static_file_config() click to toggle source
# File lib/cloudinary/static.rb, line 170
def static_file_config
  @static_file_config ||= begin
    config = Cloudinary.config.static_files || {}

    # Default
    config['images'] ||= {}
    config['images']['dirs'] ||= Cloudinary.config.static_image_dirs # Backwards compatibility
    config['images']['dirs'] ||= DEFAULT_IMAGE_DIRS
    config['images']['file_mask'] ||= DEFAULT_IMAGE_EXTENSION_MASK
    # Validate
    config.each do |group, data|
      unless data && data['dirs'] && data['file_mask']
        print "In config, static_files group '#{group}' needs to have both 'dirs' and 'file_mask' defined.\n"
        exit
      end
    end

    config
  end
end