# frozen_string_literal: true

require “shellwords”

set :docker_roles, [:docker]

def as_docker_user

user = fetch(:docker_user, nil)
if user
  as(user) do
    with(fetch(:docker_env, {})) do
      yield
    end
  end
else
  yield
end

end

namespace :deploy do

after :new_release_path, "docker:create_release"

after :updating, "docker:update"

after :published, "docker:restart"

after :reverted, "docker:revert_image"

task :restart => "docker:restart"

# Required to be defined
task :upload do
end

end

namespace :docker do

desc "create the docker release directory and pull the image if necessary"
task :create_release do
  on release_roles(fetch(:docker_roles)) do
    execute :mkdir, "-p", release_path
  end

  if fetch(:docker_repository).include?("/")
    invoke "docker:pull"
  end
end

desc "Build and tag the docker image. This task does nothing by default, but can be implemented where needed."
task :build do
end

desc "Update the configuration and command line arguments for running a docker deployment."
task :update do
  invoke("docker:copy_configs")
  invoke("docker:upload_commands")
  invoke("docker:remove_revision")
end

desc "Prune the docker engine of all dangling images, containers, and networks."
task :prune do
  on release_roles(fetch(:docker_roles)) do |host|
    as_docker_user do
      execute :docker, "system", "prune", "--force"
    end
  end
end

desc "Pull the tagged docker image from a remote repository into the local docker engine."
task :pull => :authenticate do
  docker_image_url =  "#{fetch(:docker_repository)}:#{fetch(:docker_tag)}"
  on release_roles(fetch(:docker_roles)) do |host|
    within(release_path) do
      as_docker_user do
        docker_info = capture(:docker, "pull", docker_image_url)
        digest = docker_info.match(/Digest: (sha256:[0-9a-f]+)/)
        if digest
          execute :echo, "'#{fetch(:docker_repository)}@#{digest[1]}' > DOCKER_IMAGE_URL"
        end
      end
    end
  end
end

desc "Pull the pinned docker image from the current release and tag it."
task :revert_image => :authenticate do
  on release_roles(fetch(:docker_roles)) do |host|
    within release_path do
      as_docker_user do
        docker_image_url = capture(:cat, "DOCKER_IMAGE_URL")
        if docker_image_url.include?("/")
          execute :docker, "pull", docker_image_url
        end
        execute :docker, "tag", docker_image_url, "#{fetch(:docker_repository)}:#{fetch(:docker_tag)}"
      end
    end
  end
end

desc "You must implement the docker:authenticate task if your respository requires credentials."
task :authenticate do
end

desc "Remove the revision file if it contains placeholder text"
task :remove_revision do
  on release_roles(fetch(:docker_roles)) do |host|
    within(release_path) do
      if test("[ -f #{Shellwords.escape(release_path)}/REVISION ]")
        revision = capture(:cat, "REVISION")
        if revision.include?(" ")
          execute :rm, "REVISION"
        end
      end
    end
  end
end

desc "Restart the docker containers (alias to docker:start)."
task :restart do
  on release_roles(fetch(:docker_roles)) do |host|
    within "#{fetch(:deploy_to)}/current" do
      scripts = Capistrano::DockerCluster::Scripts.new(self)
      Array(scripts.fetch_for_host(host, :docker_apps)).each do |app|
        as_docker_user do
          execute "bin/start", app, "--force"
        end
      end
    end
  end
end

desc "Start the docker containers."
task :start do
  on release_roles(fetch(:docker_roles)) do |host|
    within "#{fetch(:deploy_to)}/current" do
      scripts = Capistrano::DockerCluster::Scripts.new(self)
      Array(scripts.fetch_for_host(host, :docker_apps)).each do |app|
        as_docker_user do
          execute "bin/start", app
        end
      end
    end
  end
end

desc "Stop the docker containers."
task :stop do
  on release_roles(fetch(:docker_roles)) do |host|
    within "#{fetch(:deploy_to)}/current" do
      scripts = Capistrano::DockerCluster::Scripts.new(self)
      Array(scripts.fetch_for_host(host, :docker_apps)).each do |app|
        as_docker_user do
          execute "bin/stop", app
        end
      end
    end
  end
end

desc "Upload the commands to stop and start the application docker containers."
task :upload_commands do
  on release_roles(fetch(:docker_roles)) do |host|
    within fetch(:release_path) do
      execute(:mkdir, "-p", "bin")
      scripts = Capistrano::DockerCluster::Scripts.new(self)
      docker_cluster_path = File.join(__dir__, "..", "..", "..", "bin", "docker-cluster")
      upload! docker_cluster_path, "bin/docker-cluster"
      upload! StringIO.new(scripts.start_script(host)), "bin/start"
      upload! StringIO.new(scripts.stop_script(host)), "bin/stop"
      upload! StringIO.new(scripts.run_script(host)), "bin/run"
      execute :chmod, "a+x", "bin/*"
    end
  end
end

desc "Copy configuration files used to start the docker containers."
task :copy_configs do
  on release_roles(fetch(:docker_roles)) do |host|
    within fetch(:release_path) do
      configs = Capistrano::DockerCluster::Scripts.new(self).docker_config_map(host)
      execute(:mkdir, "-p", "config")
      configs.each do |name, local_path|
        upload! local_path, "config/#{name}"
      end
    end
  end
end

end