# encoding: utf-8
require_relative 'tasks/e2e'

################################
# Rake configuration
################################

# Paths
DERIVED_DATA_DIR = File.join('.build').freeze
RELEASES_ROOT_DIR = File.join('releases').freeze

EXECUTABLE_NAME = 'XCRemoteCache'
EXECUTABLE_NAMES = ['xclibtool', 'xcpostbuild', 'xcprebuild', 'xcprepare', 'xcswiftc', 'swiftc', 'xcswift-frontend', 'swift-frontend', 'xcld', 'xcldplusplus', 'xclipo']
PROJECT_NAME = 'XCRemoteCache'

SWIFTLINT_ENABLED = true
SWIFTFORMAT_ENABLED = true

################################
# Tasks
################################

task :prepare do
  Dir.mkdir(DERIVED_DATA_DIR) unless File.exists?(DERIVED_DATA_DIR)
end

desc 'lint'
task :lint => [:prepare] do
  puts 'Run linting'

  system("swiftformat --lint --config .swiftformat --cache ignore .") or abort "swiftformat failure" if SWIFTFORMAT_ENABLED
  system("swiftlint lint --config .swiftlint.yml --strict") or abort "swiftlint failure" if SWIFTLINT_ENABLED
end

task :autocorrect => [:prepare]  do 
  puts 'Run autocorrect'

  system("swiftformat --config .swiftformat --cache ignore .") or abort "swiftformat failure" if SWIFTFORMAT_ENABLED
  system("swiftlint autocorrect --config .swiftlint.yml") or abort "swiftlint failure" if SWIFTLINT_ENABLED
end

desc 'build package artifacts'
task :build, [:configuration, :arch, :sdks, :is_archive] do |task, args|
  # Set task defaults
  args.with_defaults(:configuration => 'debug', :sdks => ['macos'])

  unless args.configuration == 'Debug'.downcase || args.configuration == 'Release'.downcase
    fail("Unsupported configuration. Valid values: ['Debug', 'Release']. Found '#{args.configuration}''")
  end

  # Clean data generated by SPM
  # FIXME: dangerous recursive rm
  system("rm -rf #{DERIVED_DATA_DIR} > /dev/null 2>&1")

  # Build
  build_paths = []
  args.sdks.each do |sdk|
    spm_build(args.configuration, args.arch)

    # Path of the executable looks like: `.build/(debug|release)/XCRemoteCache`
    build_path_base = File.join(DERIVED_DATA_DIR, args.configuration)
    # swift-frontent integration requires that the SWIFT_EXEC is `swiftc` so create
    # a symbolic link between swiftc->xcswiftc and swift-frontend->xcswift-frontend
    system("cd #{build_path_base} && ln -s xcswiftc swiftc")
    system("cd #{build_path_base} && ln -s xcswift-frontend swift-frontend")
    sdk_build_paths = EXECUTABLE_NAMES.map {|e| File.join(build_path_base, e)}

    build_paths.push(sdk_build_paths)
  end

  puts "Build products: #{build_paths}"

  if args.configuration == 'Release'.downcase
    puts "Creating release zip"
    create_release_zip(build_paths[0])
  end
end

desc 'Build release artifacts'
task :prepare_release do
  system("rm -rf releases && rm -rf tmp")
  Rake::Task['build'].invoke("release", "x86_64-apple-macosx")
  system("mkdir -p tmp && unzip releases/XCRemoteCache.zip -d tmp/xcremotecache-x86_64")
  system("rm -rf releases")
  Rake::Task['build'].invoke("release", "arm64-apple-macosx")
  system("rake 'build[release, arm64-apple-macosx]'")
  system("mkdir -p tmp && unzip releases/XCRemoteCache.zip -d tmp/xcremotecache-arm64")
  system("rm -rf releases")
  system("mkdir -p releases && zip -jr releases/XCRemoteCache-macOS-x86_64.zip LICENSE README.md tmp/xcremotecache-x86_64")
  system("zip -jr releases/XCRemoteCache-macOS-arm64.zip LICENSE README.md tmp/xcremotecache-arm64")
  system("mkdir -p tmp/xcremotecache && ls tmp/xcremotecache-x86_64 | xargs -I {} lipo -create -output tmp/xcremotecache/{} tmp/xcremotecache-x86_64/{} tmp/xcremotecache-arm64/{}")
  system("zip -jr releases/XCRemoteCache-macOS-arm64-x86_64.zip LICENSE README.md tmp/xcremotecache")
end

desc 'run tests with SPM'
task :test do
  # Running tests
  spm_test()
end

desc 'build and run E2E tests'
task :e2e => [:build, :e2e_only]

desc 'run E2E tests without building the XCRemoteCache binary'
task :e2e_only => ['e2e:run']

################################
# Helper functions
################################

def spm_build(configuration, arch)
  spm_cmd = "swift build "\
              "-c #{configuration} "\
              "#{arch.nil? ? "" : "--triple #{arch}"} "
  system(spm_cmd) or abort "Build failure"
end

def bash(command)
  system "bash -c \"#{command}\""
end

def spm_test()
  tests_output_file = File.join(DERIVED_DATA_DIR, 'tests.log')
  # Redirect error stream with to a file and pass to the second stream output 
  spm_cmd = "swift test --enable-code-coverage 2> >(tee #{tests_output_file})"
  test_succeeded = bash(spm_cmd)
  
  abort "Test failure" unless test_succeeded
end

def create_release_zip(build_paths)
  release_dir = RELEASES_ROOT_DIR
  
  # Create and move files into the release directory
  mkdir_p release_dir
  build_paths.each {|p|
    # -r for recursive
    # -P for copying symbolic link as is
    system("cp -rP #{p} #{release_dir}")
  }
  
  output_artifact_basename = "#{PROJECT_NAME}.zip"

  Dir.chdir(release_dir) do
    # -X: no extras (uid, gid, file times, ...)
    # -x: exclude .DS_Store
    # -r: recursive
    # -y: to store symbolic links (used for swiftc -> xcswiftc)
    system("zip -X -x '*.DS_Store' -r -y #{output_artifact_basename} .") or abort "zip failure"
    # List contents of zip file
    system("unzip -l #{output_artifact_basename}") or abort "unzip failure"
  end
end
