def find(name, providers, version)
      providers = Array(providers)

      # Build up the requirements we have
      requirements = version.to_s.split(",").map do |v|
        Gem::Requirement.new(v.strip)
      end

      with_collection_lock do
        box_directory = @directory.join(dir_name(name))
        if !box_directory.directory?
          @logger.info("Box not found: #{name} (#{providers.join(", ")})")
          return nil
        end

        # Keep a mapping of Gem::Version mangled versions => directories.
        # ie. 0.1.0.pre.alpha.2 => 0.1.0-alpha.2
        # This is so we can sort version numbers properly here, but still
        # refer to the real directory names in path checks below and pass an
        # unmangled version string to Box.new
        version_dir_map = {}

        versions = box_directory.children(true).map do |versiondir|
          next if !versiondir.directory?
          next if versiondir.basename.to_s.start_with?(".")

          version = Gem::Version.new(versiondir.basename.to_s)
          version_dir_map[version.to_s] = versiondir.basename.to_s
          version
        end.compact

        # Traverse through versions with the latest version first
        versions.sort.reverse.each do |v|
          if !requirements.all? { |r| r.satisfied_by?(v) }
            # Unsatisfied version requirements
            next
          end

          versiondir = box_directory.join(version_dir_map[v.to_s])
          providers.each do |provider|
            provider_dir = versiondir.join(provider.to_s)
            next if !provider_dir.directory?
            @logger.info("Box found: #{name} (#{provider})")

            metadata_url = nil
            metadata_url_file = box_directory.join("metadata_url")
            metadata_url = metadata_url_file.read if metadata_url_file.file?

            if metadata_url && @hook
              hook_env     = @hook.call(
                :authenticate_box_url, box_urls: [metadata_url])
              metadata_url = hook_env[:box_urls].first
            end

            return Box.new(
              name, provider, version_dir_map[v.to_s], provider_dir,
              metadata_url: metadata_url,
            )
          end
        end
      end

      nil
    end
def find(name, providers, version)
      providers = Array(providers)

      # Build up the requirements we have
      requirements = version.to_s.split(",").map do |v|
        Gem::Requirement.new(v.strip)
      end

      with_collection_lock do
        box_directory = @directory.join(dir_name(name))
        if !box_directory.directory?
          @logger.info("Box not found: #{name} (#{providers.join(", ")})")
          return nil
        end

        # Keep a mapping of Gem::Version mangled versions => directories.
        # ie. 0.1.0.pre.alpha.2 => 0.1.0-alpha.2
        # This is so we can sort version numbers properly here, but still
        # refer to the real directory names in path checks below and pass an
        # unmangled version string to Box.new
        version_dir_map = {}

        versions = box_directory.children(true).map do |versiondir|
          next if !versiondir.directory?
          next if versiondir.basename.to_s.start_with?(".")

          version = Gem::Version.new(versiondir.basename.to_s)
          version_dir_map[version.to_s] = versiondir.basename.to_s
          version
        end.compact

        # Traverse through versions with the latest version first
        versions.sort.reverse.each do |v|
          if !requirements.all? { |r| r.satisfied_by?(v) }
            # Unsatisfied version requirements
            next
          end

          versiondir = box_directory.join(version_dir_map[v.to_s])
          providers.each do |provider|
            provider_dir = versiondir.join(provider.to_s)
            next if !provider_dir.directory?
            @logger.info("Box found: #{name} (#{provider})")

            metadata_url = nil
            metadata_url_file = box_directory.join("metadata_url")
            metadata_url = metadata_url_file.read if metadata_url_file.file?

            if metadata_url && @hook
              hook_env     = @hook.call(
                :authenticate_box_url, box_urls: [metadata_url])
              metadata_url = hook_env[:box_urls].first
            end

            return Box.new(
              name, provider, version_dir_map[v.to_s], provider_dir,
              metadata_url: metadata_url,
            )
          end
        end
      end

      nil
    end
Find a box in the collection with the given name and provider.

 @param [String] name Name of the box (logical name).
 @param [Array] providers Providers that the box implements.
 @param [String] version Version constraints to adhere to. Example:
   "~> 1.0" or "= 1.0, ~> 1.1"
 @return [Box] The box found, or `nil` if not found.