#!/usr/bin/env ruby

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

LKP_SRC = ENV['LKP_SRC'] || File.dirname(File.dirname(File.realpath($PROGRAM_NAME)))
LKP_USER = ENV['USER'] || `whoami`.chomp

require "#{LKP_SRC}/lib/distro_info"

TMP = "/tmp/lkp-#{LKP_USER}".freeze
ENV['TMP'] = TMP

require "#{LKP_SRC}/lib/run_env"
set_local_run
require "#{LKP_SRC}/lib/yaml"
require "#{LKP_SRC}/lib/stats"
require "#{LKP_SRC}/lib/matrix"
require "#{LKP_SRC}/lib/job2sh"
require "#{LKP_SRC}/lib/job"
require "#{LKP_SRC}/lib/result_root"
require "#{LKP_SRC}/lib/common"
require "#{LKP_SRC}/lib/log"

ENV['PATH'] = ENV['PATH'] + ":#{LKP_SRC}/bin"
ENV['BENCHMARK_ROOT'] = '/lkp/benchmarks'

$opt_result_root = 'result'
$opt_set_key_value = {}

opt_parser = OptionParser.new do |opts|
  opts.banner = 'Usage: run-local [-o RESULT_ROOT] JOBFILE'

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

  opts.on('-o RESULT_ROOT', '--output RESULT_ROOT', 'link to result directory') do |dir|
    $opt_result_root = dir
  end

  opts.on("-s 'KEY: VALUE'", "--set 'KEY: VALUE'", 'add YAML hash to job') do |key_value|
    $opt_set_key_value.merge!(YAML.load(key_value))
  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)

jobfile = ARGV[0]
unless jobfile
  puts 'No jobfile specified'
  exit 1
end

# Setup environment for user specified test case
argv = ARGV.drop(1)
argv = argv.drop(1) if argv[0] == '--'

ENV['MY_TEST_CMDLINE'] = Shellwords.join ARGV.drop(1) unless argv.empty?

if !jobfile.index('/') && !File.exist?(jobfile)
  file = LKP_SRC + '/jobs/' + jobfile
  jobfile = file if File.exist?(file)
end

def create_result_root(_result_root)
  0.upto(99) do |i|
    result_root = "#{_result_root}/#{i}"
    next if Dir.exist? result_root

    FileUtils.mkdir_p result_root, mode: 0o2775
    return result_root
  end
  log_warn "cannot create more result_roots under #{_result_root}"
  nil
end

begin
  # "#!" is defined by comment_to_symbol
  if File.readlines(jobfile).any? { |l| l.start_with?(':#! ') }
    log_warn "Jobfile is a dirty file, better to run 'lkp split-job --compatible #{jobfile}' first"
  end

  job = Job.new
  job.load(jobfile)
  unless job.atomic_job?
    log_error "Looks #{ARGV[0]} isn't a atomic jobfile, only atomic jobfile is supported"
    log_error "Please run 'lkp split-job #{ARGV[0]}' first"
    exit 1
  end
rescue StandardError
  log_warn "#{jobfile} is not a valid jobfile"
  exit 1
end

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

HOSTNAME ||= ENV['HOSTNAME'] || `hostname`.chomp
job['testbox'] = HOSTNAME
job['tbox_group'] = tbox_group(HOSTNAME)
job['kconfig'] ||= 'defconfig'
job['commit'] ||= `uname -r`.chomp!
job['rootfs'] ||= if File.exist? '/etc/os-release'
                    `grep -m1 ^ID= /etc/os-release`.split('=')[1].chomp
                  else
                    distro
                  end
job['nr_cpu'] ||= `nproc`.to_i
job['memory'] ||= `grep -w '^memory:' #{LKP_SRC}/hosts/#{HOSTNAME}`.split(' ')[1].chomp
job['compiler'] ||= File.symlink?('/usr/bin/gcc') ? File.readlink('/usr/bin/gcc') : 'gcc'
job['NO_NETWORK'] = 1
job['LKP_LOCAL_RUN'] = 1

$opt_set_key_value.each do |k, v|
  job[k] = v
end

_result_root = job._result_root
result_root = create_result_root(_result_root)
exit unless result_root
ENV['RESULT_ROOT'] = result_root
ENV['TMP_RESULT_ROOT'] = result_root

jobx = Job2sh.new(job.to_hash)
unless jobx.expand_params
  log_error "Failed to expand params!"
  exit
end

FileUtils.rm_rf TMP
Dir.mkdir TMP

job_script = result_root + '/job.sh'
File.open(job_script, 'w', 0o775) do |file|
  file.puts jobx.to_shell
end

user = ENV['USER']
save_paths(result_root, user)

system 'killall', '-q', LKP_SRC + '/bin/event/wakeup'
system job_script, 'run_job'
system LKP_SRC + '/bin/run-with-job', job_script, LKP_SRC + '/bin/post-run'
system LKP_SRC + '/bin/event/wakeup', 'job-finished'

job.save result_root + '/job.yaml'

system job_script, 'extract_stats'

stats = create_stats_matrix ENV['RESULT_ROOT']
stats['stats_source'] = result_root + '/stats.json'
unite_to(stats, _result_root)
system(LKP_SRC + '/sbin/unite-params', result_root)

MResultRootTableSet.create_tables_layout
convert_mrt(_result_root)

FileUtils.rm_f($opt_result_root)
FileUtils.ln_s(result_root, $opt_result_root)
