# Copyright 2012-2013 Crowd Favorite, Ltd.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
#  http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.

require 'tempfile'

# These methods are used by recap tasks to run commands and detect when files have changed
# as part of a deployments

module CrowdFavorite::Support::CapistranoExtensions
  # Run a command as the given user
  def as_user(user, command, pwd = deploy_to)
    sudo "su - #{user} -c 'cd #{pwd} && #{command}'"
  end

  # Run a command as root
  def as_root(command, pwd = deploy_to)
    as_user 'root', command, pwd
  end

  # Run a command as the application user
  def as_app(command, pwd = deploy_to)
    as_user application_user, command, pwd
  end

  # Put a string into a file as the application user
  def put_as_app(string, path)
    put string, "/tmp/cf-put-as-app"
    as_app "cp /tmp/cf-put-as-app #{path} && chmod g+rw #{path}", "/"
  ensure
    run "rm /tmp/cf-put-as-app"
  end

  def editor
    ENV['DEPLOY_EDITOR'] || ENV['EDITOR']
  end

  # Edit a file on the remote server, using a local editor
  def edit_file(path)
    if editor
      as_app "touch #{path} && chmod g+rw #{path}"
      local_path = Tempfile.new('deploy-edit').path
      get(path, local_path)
      CrowdFavorite::Support::ShellCommand.execute_interactive("#{editor} #{local_path}")
      File.read(local_path)
    else
      abort "To edit a remote file, either the EDITOR or DEPLOY_EDITOR environment variables must be set"
    end
  end

  # Run a git command in the `deploy_to` directory
  def git(command)
    run "cd #{deploy_to} && umask 002 && sg #{application_group} -c \"git #{command}\""
  end

  # Capture the result of a git command run within the `deploy_to` directory
  def capture_git(command)
    capture "cd #{deploy_to} && umask 002 && sg #{application_group} -c 'git #{command}'"
  end

  def exit_code(command)
    capture("#{command} > /dev/null 2>&1; echo $?").strip
  end

  def exit_code_as_app(command, pwd = deploy_to)
    capture(%|sudo -p 'sudo password: ' su - #{application_user} -c 'cd #{pwd} && #{command} > /dev/null 2>&1'; echo $?|).strip
  end

  # Find the latest tag from the repository.  As `git tag` returns tags in order, and our release
  # tags are timestamps, the latest tag will always be the last in the list.
  def latest_tag_from_repository
    result = capture_git("tag | tail -n1").strip
    result.empty? ? nil : result
  end

  # Does the given file exist within the deployment directory?
  def deployed_file_exists?(path, root_path = deploy_to)
    exit_code("cd #{root_path} && [ -f #{path} ]") == "0"
  end

  # Has the given path been created or changed since the previous deployment?  During the first
  # successful deployment this will always return true.
  def deployed_file_changed?(path)
    return true unless latest_tag
    exit_code("cd #{deploy_to} && git diff --exit-code #{latest_tag} origin/#{branch} #{path}") == "1"
  end

  Capistrano::Configuration.send :include, self
end
