#!/usr/bin/env ruby require 'fileutils' require 'getoptlong' require 'yaml' require 'bcrypt' require 'base64' require "#{File.dirname(__FILE__)}/../lib/teamster-cli" DEFAULT_UNIX_SOCKET_FILE = '/tmp/teamster.app.sock' DEFAULT_APP_STATE_FILE = '/srv/my-site/teamster.app.state' CONFIG_FILE = 'conf/teamster.conf' VERSION = File.read(File.dirname(__FILE__) + '/../VERSION') class TeamsterApp include Teamster::CLI class << self def read_options_and_run read_options run_app end def read_options opts = GetoptLong.new( ["--debug", GetoptLong::NO_ARGUMENT ], ["--version", GetoptLong::NO_ARGUMENT ], ["--prod", GetoptLong::NO_ARGUMENT ], ["--help", GetoptLong::NO_ARGUMENT ], ["--overwrite", GetoptLong::NO_ARGUMENT ], ["--local", GetoptLong::NO_ARGUMENT ], ["--no-update", GetoptLong::NO_ARGUMENT ], ["--socket-file", GetoptLong::REQUIRED_ARGUMENT], ["--state-file", GetoptLong::REQUIRED_ARGUMENT]) @opts = {}.tap do |hsh| opts.each do |opt, arg| opt = opt[/--([\w-]+)/, 1].gsub(/-/, "_").to_sym arg ||= true hsh[opt] = arg end end @opts end ALLOWED_COMMANDS = [ :init, :list, :create, :delete, :remove, :export, :import, :update, :start, :stop, :restart ] def run_app if @opts[:help] quit detailed_usage elsif @opts[:version] quit show_version elsif ARGV.size > 0 command = ARGV.shift.to_sym args = ARGV if ALLOWED_COMMANDS.include?(command) send command, *args else unknown command end else quit usage end end private # --{ COMMANDS }-- # def unknown(command) quit "\nUNKNOWN COMMAND: #{command}\nFor help, run command: teamster --help", 1 end def init(*args) current_working_folder = Dir.pwd content = File.dirname(__FILE__) + '/../content' @config = {} puts "Initializing Teamster in current folder." puts "Creating required content..." FileUtils.mkdir_p "conf" create_config FileUtils.mkdir_p "data" create_user FileUtils.cp_r "#{content}/views", current_working_folder FileUtils.cp_r "#{content}/public", current_working_folder create_file "config.ru", "config_ru" FileUtils.mkdir_p "lib/teamster-adapters" create_file "lib/teamster-adapters.rb", "teamster_adapters" puts "Teamster initialized!" puts "- Run \"teamster create \" to create a placeholder adapter." puts "- Run \"teamster start\" to start teamster!" end def start(*) puts "Starting teamster..." if File.exists?(CONFIG_FILE) if @opts[:prod] socket_file = @opts[:socket_file] || DEFAULT_UNIX_SOCKET_FILE state_file = @opts[:state_file] || DEFAULT_APP_STATE_FILE Thread.new { exec "puma -d -b unix://#{socket_file} -S #{state_file}" } else Thread.new { exec "rackup -p 9292" } end else quit "\nERROR: Teamster not initialized!\nUnable to start Teamster. Please initialize first by running \"teamster init\"." end end def stop(*) puts "Stopping teamster..." state_file = @opts[:state_file] || DEFAULT_APP_STATE_FILE if File.exists? state_file Thread.new { exec "pumactl -S #{state_file} stop" } else quit "\nERROR: state file does not exists: #{state_file}\nUnable to stop teamster." exit 1 end end def restart(*) puts "Restarting teamster..." state_file = @opts[:state_file] || DEFAULT_APP_STATE_FILE if File.exists? state_file Thread.new { exec "pumactl -S #{state_file} restart" } else quit "\nERROR: state file does not exists: #{state_file}\nUnable to restart teamster." end end def create(*args) name = args.join(' ') if name =~ /_/ quit "Does not support adapter names containing underscores." end create_adapter_for name end def update(*args) name = if args.empty? nil else args.join(' ') end if name update_adapter name else update_new_adapters update_existing_adapters end end def delete(*args) unless @opts[:no_update] update_new_adapters update_existing_adapters end name = args.join(' ') config = YAML.load_file(CONFIG_FILE) adapters = config.fetch('adapters') selected_adapter = adapters.find {|e| e.fetch("name") == name} if selected_adapter files = selected_adapter.fetch("files") confirmation = ask_user "Are you sure you want to delete adapter \"#{name}\"? [y/N]" if confirmation =~ /^y$|^yes$/i files.each do |file| FileUtils.rm file end adapters.delete_if {|e| e.fetch("name") == name} File.open(CONFIG_FILE, 'w') {|fh| fh.write config.to_yaml} quit "Successfully deleted adapter: #{name}" else quit "Deletion of adapter \"#{name}\" cancelled." end else quit "Unable to find adapter: #{name}" end end alias_method :remove, :delete def list(*args) unless @opts[:no_update] update_new_adapters update_existing_adapters end local = @opts[:local] || true adapters = fetch_adapters adapter_names = [].tap do |arr| adapters.each {|hsh| arr << hsh.fetch('name')} end puts puts "Adapters In Current Instance:" adapter_names.each {|name| puts "- #{name}"} end def import(*args) name = args.join(' ') quit "Import not supported for now." end def export(*args) unless @opts[:no_update] update_new_adapters update_existing_adapters end name = args.join(' ') selected_adapter = fetch_adapter name if selected_adapter files = selected_adapter.fetch("files") export_adapter name, files else quit "Adapter not found: #{name}" end end def fetch_adapters YAML.load_file(CONFIG_FILE).fetch('adapters') end def fetch_adapter(name) adapters = fetch_adapters adapters.find {|e| e.fetch("name") == name} end end end TeamsterApp.read_options_and_run