#!/usr/bin/env ruby

LKP_SRC = ENV['LKP_SRC'] || File.dirname(File.dirname(File.realpath($PROGRAM_NAME)))

require "#{LKP_SRC}/lib/job"
require "#{LKP_SRC}/lib/log"
require "#{LKP_SRC}/lib/distro_info"
require 'optparse'
require 'ostruct'

opt_output_path = '.'
opt_set_key_value = {}

options = OptionParser.new do |opts|
  opts.banner = 'Usage: split-job [options] jobs...'

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

  opts.on('-o PATH', '--output PATH', 'output path') do |path|
    if File.directory? path
      opt_output_path = path
    else
      log_error "#{path}: no such directory"
      exit
    end
  end

  opts.on('-c CONFIG', '--config CONFIG', 'test kernel config') { |kconfig| @opt_kconfig = kconfig }

  opts.on('-k COMMIT', '--kernel COMMIT', 'test kernel commit') { |commit| @opt_commit = commit }

  opts.on('-t HOSTNAME', '--test-box HOSTNAME', 'test box') { |testbox| @opt_testbox = testbox }

  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('--compatible', 'refine a dirty job file') { @opt_compatible = true }

  opts.on('--any', 'save one single random atom job') { @opt_any = true }

  opts.on('--no-defaults', 'do not load the defaults headers') { @opt_no_defaults = true }

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

options.parse!(ARGV)

# Example usage:
#
# $ split-job jobs/aim7-fs-1brd.yaml fs=xfs
#
# This is be handy for daily operations, however may confuse job files
# containing '=' in file name as key/value pairs. So please use the more
# formal -s 'key: value' in scripts.
ARGV.delete_if do |arg|
  if arg.index '='
    opt_set_key_value.merge! YAML.load arg.sub(/=/, ': ')
    true
  else
    false
  end
end

if ARGV.size.zero?
  puts options
  exit
end

@opt_testbox ||= `hostname`.chomp
atom_jobs = []

distroinfo = LKP::DistroInfo.instance

def refine_job_file(jobfile)
  # "#!" is defined in comment_to_symbol
  return jobfile if File.readlines(jobfile).none? { |l| l.start_with?(':#! ') }

  # job file is a dirty yaml which may contains invalid values
  file = Tempfile.open do |f|
    p = true
    File.readlines(jobfile).each do |line|
      p = !line.match(/^:#! .*\.yaml:$/).nil? if line.start_with?(':#! ')
      f.puts line if p
    end
    f
  end
  file.path
end

ARGV.each do |jobfile|
  jobs = Job.new
  jobfile = refine_job_file(jobfile) if @opt_compatible
  jobs.load(jobfile, true) || next
  jobs['kconfig'] = @opt_kconfig if @opt_kconfig
  jobs['commit'] = @opt_commit if @opt_commit
  jobs['testbox'] = @opt_testbox
  jobs['arch'] ||= distroinfo.systemarch
  jobs['tbox_group'] = tbox_group(@opt_testbox)
  jobs['node_roles'] = 'server client' if jobs['cluster']
  jobs[:no_defaults] = true if @opt_no_defaults
  jobs.overrides = opt_set_key_value
  prefix = opt_output_path + '/' + File.basename(jobfile, '.yaml')
  jobs.each_jobs do |job|
    unit_jobfile = prefix + '-' + job.path_params
    Job::EXPAND_DIMS.select { |dim| dim =~ /commit/ }
                    .each { |dim| unit_jobfile += '-' + job[dim] if job[dim] }
    unit_jobfile += '-' + rootfs_filename(job['rootfs']) if job['rootfs']
    unit_jobfile += '.yaml'
    if @opt_any
      atom_jobs << [jobfile, unit_jobfile, deepcopy(job)]
    else
      job.save unit_jobfile
      puts "#{jobfile} => #{unit_jobfile}"
    end
  end
end

if @opt_any
  i = rand(atom_jobs.size)
  job = atom_jobs[i]
  job[2].save job[1]
  puts "#{job[0]} => #{job[1]}"
end
