karlfreeman/multi_sync

View on GitHub
lib/multi_sync/sources/manifest_source.rb

Summary

Maintainability
A
1 hr
Test Coverage
require 'yaml'
require 'json'
require 'multi_sync/source'
require 'multi_sync/resources/local_resource'

module MultiSync
  class ManifestSource < Source
    def files
      files = []
      # create a local_resource from each file
      # making sure to skip any that do not match the include/exclude patterns
      manifest_hash.each { |key, value|
        path = source_dir + key
        next if !path.fnmatch?(include.to_s) || path.fnmatch?(exclude.to_s || '')
        file = path_to_local_resource(path, mtime: value['mtime'], digest: value['digest'], content_length: value['size'])
        files << file
      }
      files.sort
    end

    private

    def manifest_hash
      manifest_hash = {}
      # ::ActionView::Base has a shortcut to the manifest file
      # otherwise lets hunt down that manifest file!
      if defined?(::ActionView::Base) && ::ActionView::Base.respond_to?(:assets_manifest)
        manifest_hash = ::ActionView::Base.assets_manifest.files
      else
        manifest_path = Dir.glob(source_dir + 'manifest*.{json,yaml,yml}').max { |f| File.ctime(f) }
        manifest_hash = parse_manifest(manifest_path)
      end
      manifest_hash
    end

    def parse_manifest(manifest_path)
      manifest_hash = {}
      manifest_data = File.read(manifest_path)

      # manifest files can be YAML or JSON but Sprockets::Manifest isn't backwards compatible with that in mind :(
      case File.extname(manifest_path)
      when '.json'
        manifest_hash = JSON.load(manifest_data)
      when '.yml', '.yaml'
        manifest_hash = YAML.load(manifest_data)
      else
        fail ArgumentError, "Unknown manifest type: #{manifest_path}"
      end

      # different versions of Sprockets have different manifest layouts, lets try and work around this by checking for the presence of "files" and "assets" in the manifest first
      # else we know it must be an old manifest file, so its root is "files"
      if manifest_hash.key?('files') || manifest_hash.key?('assets')
        manifest_hash = manifest_hash['files']
      else

        # index.* files are special and should be ignored from sync
        # something which seems to only happen in older versions of Sprockets
        manifest_hash.delete_if { |key, _|
          key.include?('/index.')
        }

        # lets manipulate this older manifest to appear similiar to the newer manifest's "files"
        modified_manifest_hash = {}
        manifest_hash.each { |key, value|
          modified_manifest_hash[value] = {
            'logical_path' => key,
            'mtime' => nil,
            'size' => nil,
            'digest' => nil
          }
        }

        manifest_hash = modified_manifest_hash

      end

      manifest_hash
    end
  end
end