$stdout.sync = true

namespace :environments do
  desc "Update one or more branches "
  task :update, :branch do |_, args|
    branch = args[:branch] || 'all'

    log "Pruning origin"
    git(:remote, :prune, :origin)

    repo_dir  = ENV['ROOT_DIR'] || '/opt/puppet'
    envs_dir  = ENV['PUPPET_ENV_DIR'] || "#{ROOT_DIR}/environments"

    log "Loading list of branches"

    all_branches  = git(:branch, '-a').split(/\W*\n\W*/)
    branches      = all_branches.map {|r| remote_branch_name(r) }.compact

    # Unless specified, only deploy the requested branch
    branch.eql?('all') ? deploy = branches : deploy = branch

    Rake::Task['environments:cleanup'].invoke(envs_dir, branches)
    Rake::Task['environments:setup'].invoke(envs_dir, repo_dir, deploy)
    Rake::Task['environments:symlink'].invoke(envs_dir)
  end

  desc "Clean up old branches from upstream"
  task :cleanup, :dir, :branches do |_, args|
    dir, branches = args[:dir], args[:branches]

    log "Cleaning up deleted branches from #{Dir.pwd}"

    Dir.chdir(dir) do
      current_envs = Dir['*']

      current_envs.each do |env|
        next if env == 'current_working_directory'
        next if branches.include? env
        next if branches.any?{ |branch| branch.gsub(/\W/,'_') == env }
        puts "Removing environment #{env}"
        FileUtils.rm_rf env
      end
    end
  end

  desc "Deploy a branch"
  task :setup, :env_dir, :repo_dir, :branches do |_, args|
    environments_dir, repo_dir, branches = args[:env_dir], args[:repo_dir], args[:branches]

    Array(branches).each do |branch|
      log "Setting up branch #{branch} from #{Dir.pwd}"

      env_checkout = "#{environments_dir}/#{branch.gsub(/\W/,'_')}"

      Dir.chdir(repo_dir) do
        log "Updating git root from #{Dir.pwd}"
        git(:fetch, '--all')

        log "Running gc on git root."
        git(:gc, '--auto')
      end

      log "Cloning initial branch environment #{branch}"
      git(:clone, '--mirror', repo_dir, "#{env_checkout}.tmp/.git")

      Dir.chdir("#{env_checkout}.tmp") do
        log "Turning bare mirror into regular repository"
        git(:config, '--bool', 'core.bare', 'false')
        log "Resetting branch environment to origin/#{branch}"
        git(:reset, '--hard', "origin/#{branch}")

        local_branch_sha = git('show', '-s', '--pretty=format:%H', 'HEAD').strip
        log "Environment #{branch} is currently on #{local_branch_sha}"
      end

      log "Deploying new branch environment #{branch}"
      FileUtils.mv env_checkout, "#{env_checkout}.old" if File.directory? env_checkout
      FileUtils.mv "#{env_checkout}.tmp", env_checkout
      FileUtils.rm_rf "#{env_checkout}.old" if File.directory? "#{env_checkout}.old"
    end
  end

  task :symlink, :environments_dir do |_, args|
    environments_dir = args[:environments_dir]

    unless Dir.exists?("#{environments_dir}/production") do
      log "Creating production symlinks"
      Dir.chdir(environments_dir) do
        ln_nfs 'master', 'production'
      end
    end
    end
    end
end