# frozen_string_literal: true

namespace :rustup do

task :wrapper do
  on release_roles(fetch(:rustup_roles)) do
    execute :mkdir, '-p', "#{fetch(:tmp_dir)}/#{fetch(:application)}/"
    upload! StringIO.new(
      "#!/bin/bash -e\nsource \"#{fetch(:rustup_env)}\"\nexec \"$@\""
    ), "#{fetch(:tmp_dir)}/#{fetch(:application)}/rustup-exec.sh"
    execute :chmod, '+x', "#{fetch(:tmp_dir)}/#{fetch(:application)}/rustup-exec.sh"
  end
end

task :map_bins do
  rustup_prefix = fetch(:rustup_prefix, -> {
    "#{fetch(:tmp_dir)}/#{fetch(:application)}/rustup-exec.sh"
  })
  fetch(:rustup_map_bins).each do |command|
    SSHKit.config.command_map.prefix[command.to_sym].unshift(rustup_prefix)
  end
end

desc <<-DESC
      Run command in the rustup environment.

      You can override any of these defaults by setting the variables shown below.

        set :cargo_target_path, nil
        set :rustup_exec_roles, :all
        set :rustup_exec_env_variables, {}

      This task is strictly opt-in. If you want to run it on every deployment \
      before you run cargo build, add the following to your deploy.rb.

        after 'cargo:install', :run_migration do
          set :rustup_exec_cmd, 'diesel migration run'
          invoke 'rustup:exec'
        end
DESC
task :exec do
  on roles fetch(:rustup_exec_roles, :all) do
    within fetch(:cargo_target_path, release_path) do
      with fetch(:rustup_exec_env_variables, {}) do
        rustup_exec_cmd = fetch(:rustup_exec_cmd).split(' ')
        unless rustup_exec_cmd.empty?
          execute(*rustup_exec_cmd)
        end
      end
    end
  end
end

end

Capistrano::DSL.stages.each do |stage|

after stage, 'rustup:wrapper'
after stage, 'rustup:map_bins'

end

namespace :cargo do

desc <<-DESC
      Install cargo packages.

      You can override any of these defaults by setting the variables shown below.

        set :cargo_target_path, nil
        set :cargo_install_roles, :all
        set :cargo_install_env_variables, {}
        set :cargo_install_crates, []

      cargo_install_crates is and Array or String or Hash :

        set :cargo_install_crates, ['diesel_cli', {name: 'cargo-watch', flags: ['-f']}]

      This task is strictly opt-in. If you want to run it on every deployment \
      before you run cargo build, add the following to your deploy.rb.

        before 'cargo:build', 'cargo:install'
DESC
task :install do
  on roles fetch(:cargo_install_roles, :all) do
    cargo_crates = fetch(:cargo_install_crates, [])
    unless cargo_crates.empty?
      within fetch(:cargo_target_path, release_path) do
        with fetch(:cargo_install_env_variables, {}) do
          cargo_crates.each do |crates_def|
            if crates_def.is_a? String
              crates_def = { name: crates_def, flags: [] }
            end
            execute :cargo, 'install', *crates_def[:flags], '--', crates_def[:name]
          end
        end
      end
    end
  end
end

desc <<-DESC
      Install the project dependencies via cargo, and build the project.

      You can override any of these defaults by setting the variables shown below.

        set :cargo_target_path, nil
        set :cargo_build_roles, :all
        set :cargo_build_env_variables, {}
        set :cargo_build_flags, ['--release']
DESC
task :build do
  on roles fetch(:cargo_build_roles, :all) do
    within fetch(:cargo_target_path, release_path) do
      with fetch(:cargo_build_env_variables, {}) do
        cargo_build_flags =  fetch(:cargo_build_flags, ['--release'])
        execute :cargo, 'build', *cargo_build_flags
      end
    end
  end
end

before 'deploy:updated', 'cargo:build'

end

namespace :load do

task :defaults do
  set :rustup_env, -> {
    rustup_env = fetch(:rustup_custom_path)
    rustup_env || '$HOME/.cargo/env'
  }

  set :rustup_roles, fetch(:rustup_roles, :all)
  set :rustup_map_bins, %w{rustc cargo}
end

end