# frozen_string_literal: true require 'fspath' require 'image_optim/bin_resolver/bin' class ImageOptim # Handle selection of directory with binaries most suitable for current # operating system and architecture module Pack # Path to binary, last two parts are expect to be os/arch class Path # Path provided to initialize as FSPath attr_reader :path # Intended os attr_reader :os # Inteded architecture attr_reader :arch # Receive path, use last part for arch and last but one part for os def initialize(path) @path = FSPath(path) @os, @arch = @path.basename.to_s.split('-', 2) end # Return path converted to string def to_s path.to_s end # Cached array of BinResolver::Bin instances for each bin def bins @bins ||= bin_paths.map do |bin_path| BinResolver::Bin.new(bin_path.basename.to_s, bin_path.to_s) end end # Return true if all bins can execute and return version def all_bins_working? bins.all?(&:version) end # Return true if all bins can't execute and return version def all_bins_failing? bins.none?(&:version) end # List of bins which can execute and return version def working_bins bins.select(&:version) end # List of bins which can't execute and return version def failing_bins bins.reject(&:version) end private # All children except those starting with 'lib' def bin_paths path.children.reject{ |child| child.basename.to_s.start_with?('lib', '.') } end end # downcased `uname -s` OS = begin `uname -s`.strip.downcase rescue Errno::ENOENT 'unknown' end # downcased `uname -m` ARCH = begin `uname -m`.strip.downcase rescue Errno::ENOENT 'unknown' end # Path to vendor at root of image_optim_pack VENDOR_PATH = FSPath('../../../vendor').expand_path(__FILE__) # List of paths PATHS = VENDOR_PATH.glob('*-*').map{ |path| Path.new(path) } class << self # Return path to directory with binaries # Yields debug messages if block given def path ordered_by_os_arch_match.find do |path| yield "image_optim_pack: #{debug_message(path)}" if block_given? path.all_bins_working? end end private # Order by match of os and architecture def ordered_by_os_arch_match PATHS.sort_by do |path| [path.os == OS ? 0 : 1, path.arch == ARCH ? 0 : 1] end end # Messages based on success of getting versions of bins def debug_message(path) case when path.all_bins_working? "all bins from #{path} worked" when path.all_bins_failing? "all bins from #{path} failed" else "#{path.failing_bins.map(&:name).join(', ')} from #{path} failed" end end end end end