– # Yast rake # # Copyright © 2017 SUSE LLC # This library is free software; you can redistribute it and/or modify # it only under the terms of version 2.1 of the GNU Lesser General Public # License as published by the Free Software Foundation. # # This library is distributed in the hope that it will be useful, but WITHOUT # ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS # FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more # details. # # You should have received a copy of the GNU Lesser General Public # License along with this library; if not, write to the Free Software # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA ++

require “shellwords” require “open3” require “tempfile”

namespace :build_dependencies do

# Read the multi build targets from the "_multibuild" file.
# @return [Array<String>] list of multi build targets or empty Array if the
#   "_multibuild" file does not exist
def multibuild_flavors
  flavors = []

  # parse the _multibuild XML file if it is present
  mbfile = File.join(Packaging::Configuration.instance.package_dir, "_multibuild")
  if File.exist?(mbfile)
    require "rexml/document"
    doc = REXML::Document.new(File.read(mbfile))
    doc.elements.each("//multibuild/flavor | //multibuild/package") do |node|
      flavors << node.text.strip
    end
  end

  puts "Found multibuild targets: #{flavors.join(", ")}" if verbose && !flavors.empty?
  flavors
end

# Read the build dependencies from a file
def buildrequires_from_file(file)
  stdout = `rpmspec -q --buildrequires #{file.shellescape}`
  raise "Parsing #{file} failed" unless $?.success?
  stdout.split("\n")
end

# Read the build dependencies from all spec files. For multi build packages
# evaluate all package flavors.
# @return [Array<String>] list of build dependencies
def buildrequires
  buildrequires = []
  # OBS additionally runs a default build with empty flavor in multi build packages,
  # for simplification use it also for single build packages
  flavors = multibuild_flavors + [ "" ]
  Dir.glob("#{Packaging::Configuration.instance.package_dir}/*.spec").each do |spec_file|
    # replace the "@BUILD_FLAVOR@" placeholder by each flavor defined
    flavors.each do |flavor|
      spec_content = File.read(spec_file).gsub!("@BUILD_FLAVOR@", flavor)

      if spec_content.nil?
        # no replacement, use the file directly
        buildrequires.concat(buildrequires_from_file(spec_file))
      else
        # rpmspec can only read a file, write the processed data to a temporary file
        Tempfile.create(["rake_build_deps-", ".spec"]) do |tmp|
          tmp.write(spec_content)
          tmp.flush
          buildrequires.concat(buildrequires_from_file(tmp.path))
        end
      end
    end
  end

  # remove the duplicates and sort the packages for easier reading
  buildrequires.uniq!
  buildrequires.sort!

  buildrequires
end

desc "Print the packages required for building"
task :list do
  puts buildrequires.join(" ")
end

desc "Install the packages required for building"
task :install do
  escaped_list = buildrequires.map { |b| Shellwords.escape(b) }.join(" ")

  if escaped_list.empty?
    puts "Nothing to install, *.spec file not found or no build dependencies defined"
  else
    sudo = Process.euid.zero? ? "" : "sudo"
    interactive = $stdin.tty? ? "" : "--non-interactive"
    # allow package downgrade to avoid failures in CI when the installed
    # packages are higher than the available ones
    cmd = "#{sudo} zypper #{interactive} install --allow-downgrade #{escaped_list}"
    sh(cmd)
  end
end

end