#!/usr/bin/env oo-ruby
#--
# Copyright 2013 Red Hat, Inc.
#
# 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 'rubygems'
require 'etc'
require 'optparse'
require 'ostruct'
require 'openshift-origin-node/utils/shell_exec'
require 'openshift-origin-node/model/cartridge_repository'

module OpenShift
  class AdminCartridgeCartridgeRepository
    def apply(options)
      repository = OpenShift::CartridgeRepository.instance
      case options.action
        when :install
          dirs = if options.recursive
                   Dir[File.join(options.source, '/*')].select { |d| File.directory?(d) }
                 else
                   [options.source]
                 end

          dirs.each do |dir|
            begin
              repository.install(dir)
            rescue OpenShift::Utils::ShellExecutionException => e
              $stderr.puts "install failed for #{dir}: #{e.message}" if options.verbose
              $stderr.puts e.backtrace.join("\n") if options.verbose
            end
          end
        when :list
          return repository.to_s
        when :erase
          repository.erase(options.name, options.version, options.cartridge_version)
      end
      'succeeded'
    end
  end

  class AdminCartridgeMcollective
    def apply(options)
      buffer = ''
      case options.action
        when :install
          dirs = if options.recursive
                   Dir[File.join(options.source, '/*')].select { |d| File.directory?(d) }
                 else
                   [options.source]
                 end

          dirs.each do |dir|
            out, _, _ = Utils::oo_spawn("mco rpc -q openshift cartridge_repository action=install path=#{dir}")
            buffer << out
          end
        when :list
          buffer, _, _ = Utils::oo_spawn('mco rpc -q openshift cartridge_repository action=list',
                                         expected_exitstatus: 0)
        when :erase
          command = %Q(mco rpc openshift cartridge_repository action=erase \
                       name="#{options.name}" version="#{options.version}" cartridge_version="#{options.cartridge_version}")
          buffer, _, _ = Utils::oo_spawn(command,
                                         expected_exitstatus: 0)
      end

      buffer.squeeze!("\n")
    end
  end
end

options = OpenStruct.new(verbose: false, recursive: false)
parser  = OptionParser.new do |opts|
  opts.banner = 'Usage: --action ACTION [--recursive] [--mco] [--source directory] [--name NAME --version VERSION --cartridge-version VERSION]'
  opts.separator ''
  opts.separator 'Options:'

  opts.on('-a', '--action ACTION', 'one of <install|list|erase>')         { |o| options.action = o.to_sym }
  opts.on('-s', '--source path', 'Directory of the cartridge to install') { |o| options.source = File.expand_path(o) }
  opts.on('--mco', 'Issue action via mcollective agent')                  { |o| options.mco    = o }

  opts.on('-R', '--recursive', 'Source is assumed to point to a directory containing cartridge directories') do |o|
    options.recursive = true
  end

  opts.on('-l', '--list', 'List cartridges in repository')                      { options.action              ||= :list }
  opts.on('-n', '--name NAME', 'Name of cartridge to erase')                    { |o| options.name              = o }
  opts.on('-v', '--version VERSION', 'Version of packaged software to erase')   { |o| options.version           = o }
  opts.on('-c', '--cartridge_version VERSION', 'Version of cartridge to erase') { |o| options.cartridge_version = o }

  opts.on_tail('-d', '--debug', 'enable additional output') { options.verbose = true }
  opts.on('--offline', 'ignored') {}
  # -h, --help implicate
end

parser.parse!

unless options.action
  $stderr.puts "--action required argument:\n" + parser.help
  exit 1
end

mandatory = {
    install: [:source],
    list:    [],
    erase:   [:name, :version, :cartridge_version]
}

missing = mandatory[options.action].select { |o| not options.respond_to? o }
unless missing.empty?
  $stderr.puts "Missing arguments: #{missing}\n" + parser.help
  exit 1
end

begin
  if options.mco
    puts OpenShift::AdminCartridgeMcollective.new.apply(options)
  else
    puts OpenShift::AdminCartridgeCartridgeRepository.new.apply(options)

    if [:install, :erase].include?(options.action)
      OpenShift::Utils::oo_spawn('pkill -USR1 -f /usr/sbin/mcollectived')
    end
  end
rescue OpenShift::Utils::ShellExecutionException => e
  $stderr.puts "\nOperation failed: #{e.stdout}\n#{e.stderr}\n"
  $stderr.puts e.backtrace.join("\n") if options.verbose
  exit e.rc
end
