#!/usr/bin/env ruby

require 'optparse'
require 'ostruct'
require 'fileutils'

HOSTNAME = ENV['HOSTNAME'] || `hostname`.chomp
ENV['LKP_SRC'] ||= File.dirname File.dirname File.realpath $PROGRAM_NAME
LKP_SRC = ENV['LKP_SRC'] || File.dirname(File.dirname(File.realpath($PROGRAM_NAME)))

require "#{LKP_SRC}/lib/yaml"
require "#{LKP_SRC}/lib/job"
require "#{LKP_SRC}/lib/distro_info"
require "#{LKP_SRC}/lib/install"
require "#{LKP_SRC}/lib/constant"

TMP = LKP_SRC + '/tmp'

if `whoami`.chomp != 'root'
  puts 'Please run as root to install packages'
  exit 1
end

$opt_hdd = []
$opt_ssd = []

opt_parser = OptionParser.new do |opts|
  opts.banner = 'Usage: setup-local [options] <script>/<jobfile>'

  opts.separator ''
  opts.separator 'options:'

  opts.on('--hdd partition', 'HDD partition for IO tests') do |hdd|
    $opt_hdd << hdd
  end

  opts.on('--ssd partition', 'SSD partition for IO tests') do |ssd|
    $opt_ssd << ssd
  end

  opts.on_tail('-h', '--help', 'Show this message') do
    puts opts
    exit
  end
end

argv = if ARGV == []
         ['-h']
       else
         ARGV
       end
opt_parser.parse!(argv)

scripts = []
ARGV.each do |arg|
  if arg =~ /.yaml/
    job = Job.new
    job.load(arg)
    job.each_program(:workload_and_monitors) do |k, _v|
      scripts << k
    end
  elsif File.executable? arg
    scripts << arg.split('/')[-1]
  end
end

if scripts.empty?
  puts 'No valid script or jobfile specified'
  exit 1
end
scripts.uniq!

def make_wakeup
  return if File.executable? LKP_SRC + '/bin/event/wakeup'

  system "cd #{LKP_SRC}/bin/event && make wakeup"
end

def create_lkp_dirs
  FileUtils.mkdir_p TMP
  FileUtils.mkdir_p KTEST_PATHS_DIR
  FileUtils.mkdir_p '/lkp/benchmarks'
end

def create_host_config
  host_config = LKP_SRC + "/hosts/#{HOSTNAME}"
  if File.exist? host_config
    puts 'reusing ' + host_config
  else
    mem_kb = File.open('/proc/meminfo').gets.split[1].to_i
    mem_gb = mem_kb >> 20
    mem_gb = (mem_gb + 3) & 0xfffffffc
    nr_cpu = `getconf _NPROCESSORS_CONF`
    File.open(host_config, 'w') do |file|
      file.puts "memory: #{mem_gb}G"
      file.puts "hdd_partitions: #{$opt_hdd.join ' '}"
      file.puts "ssd_partitions: #{$opt_ssd.join ' '}"
      file.puts "nr_cpu: #{nr_cpu}"
    end
  end
  host_group_config = LKP_SRC + "/hosts/#{tbox_group(HOSTNAME)}"
  FileUtils.cp(host_config, host_group_config) unless File.exist? host_group_config
end

def install_packages(script, distro)
  packages = get_dependency_packages(distro, script)
  dev_packages = get_dependency_packages(distro, script + '-dev')
  packages |= dev_packages
  return if packages.empty?

  return if system "#{LKP_SRC}/distro/installer/#{distro}", *packages

  puts "Cannot install some packages in #{LKP_SRC}/distro/#{distro}/#{script}"
  exit 1
end

def install_benchmarks(script, distro)
  return unless File.file? "#{LKP_SRC}/pack/#{script}"

  if File.basename(File.realpath "#{LKP_SRC}/pack/#{script}") == 'perf'
    `perf -v 2>/dev/null`
    return if $?.success?
  end

  pkg_name = script.tr('_', '-') + '-LKP'
  distroinfo = LKP::DistroInfo.instance
  arch = distroinfo.systemarch
  puts "Making #{script} benchmark for #{distro}"

  if system "#{LKP_SRC}/sbin/pack -d #{distro} -c #{script}"
    puts "Installing #{pkg_name}..."

    case distro
    when 'debian', 'ubuntu'
      system "dpkg -i /tmp/#{pkg_name}.deb"
    when 'fedora'
      system "rpm -ivh --replacepkgs /tmp/#{pkg_name}/RPMS/#{pkg_name}.#{arch}.rpm"
    else
      puts "Just make /lkp/benchmarks/#{script}-#{arch}.cgz"
    end
  else
    puts "Making #{pkg_name} failed"
  end
end

distroinfo = LKP::DistroInfo.instance
distro = distroinfo.systemnamel

unless File.executable? "#{LKP_SRC}/distro/installer/#{distro}"
  puts "Unsupport #{distro} system, cannot install packages."
  exit 1
end

make_wakeup
create_lkp_dirs
create_host_config
install_packages('lkp', distro)
install_packages('makepkg', distro)

scripts.each do |script|
  install_packages(script, distro)
  install_benchmarks(script, distro)
end
