module Gem2Rpm class Distro FEDORA = :fedora PLD = :pld OPENSUSE = :opensuse DEFAULT = :default ROLLING_RELEASES = %w[rawhide factory tumbleweed].freeze OsRelease = Struct.new :os, :version # Returns struct with OS detected based on release files. # # Distro.os_release.os contains either one of supported distributions # (:fedora, :pld, :opensuse) or :default for unrecognized/unsupported # distributions. # # Distro.os_release.version contains version if it is possible to detect. def self.os_release @os_release ||= begin os_release = OsRelease.new DEFAULT grouped_release_files = release_files.group_by do |file| File.basename(file)[/os-release|fedora|redhat|SuSE|pld/] || 'unrecognized' end # Try os-release first. if (os_release_files = grouped_release_files['os-release']) content = File.open(os_release_files.first, Gem2Rpm::OPEN_MODE, &:read) begin os_release.os = content[/^ID=['"]?(.*?)['"]?$/, 1].to_sym os_release.version = content[/^VERSION_ID=['"]?(.*?)['"]?$/, 1] rescue end end # If os-release failed (it is empty or has not enough information), # try some other release files. if os_release.os == DEFAULT if (fedora_release_files = grouped_release_files['fedora']) os_release.os = FEDORA versions = [] fedora_release_files.each do |file| /\d+/ =~ File.open(file, OPEN_MODE).readline versions << Regexp.last_match.to_s if Regexp.last_match end versions.uniq! os_release.version = versions.first if versions.length == 1 elsif grouped_release_files['redhat'] # Use Fedora's template for RHEL ATM. os_release.os = FEDORA elsif grouped_release_files['SuSE'] os_release.os = OPENSUSE elsif grouped_release_files['pld'] os_release.os = PLD end end os_release end end def self.nature template_by_os_version(os_release.os, os_release.version) || DEFAULT.to_s end # Provides list of release files found on the system. def self.release_files @release_files ||= Dir.glob('/etc/{os-release,*{_version,-release}}*').uniq.select { |e| File.file? e } end # Allows to override release files list. def self.release_files=(files) @os_release = nil @release_files = files end # Tries to find best suitable template for specified os and version. def self.template_by_os_version(os, version) os_templates = Template.list.grep(/#{os}.*\.spec\.erb/) os_templates.each do |file| # We want only distro RubyGems templates to get the right versions next unless file =~ /^#{os}((-([0-9]+\.{0,1}[0-9]+){0,}){0,}(-(#{ROLLING_RELEASES.join('|')})){0,1}).spec.erb/ if (match = Regexp.last_match) return file.gsub('.spec.erb', '') if in_range?(version, match[1].to_s.split('-').drop(1)) || match[1].empty? end end nil end def self.in_range?(version, range) return nil unless range if range.length == 1 return true if range.first.to_s == version.to_s else # range: [xx, yy] if range[0].to_s <= version.to_s return true if ROLLING_RELEASES.include?(range[1]) || (version.to_s <= range[1].to_s) end end false end end end