module CapistranoMulticonfigParallel # class that holds the options that are configurable for this gem module Configuration extend ActiveSupport::Concern class_methods do attr_accessor :configuration def configuration @config ||= Configliere::Param.new @config.use :commandline command_line_params.each do |param| @config.define param[:name], type: param[:type], description: param[:description], default: param[:default] end ARGV.clear CapistranoMulticonfigParallel.original_args.each { |a| ARGV << a } @config.read config_file if File.file?(config_file) @config.merge(Settings.use(:commandline).resolve!) @config.use :config_block @config.finally do |c| check_configuration(c) end @config.resolve! end def default_config @default_config ||= Configliere::Param.new @default_config.read File.join(internal_config_directory, 'default.yml') @default_config.resolve! end def config_file File.join(CapistranoMulticonfigParallel.detect_root.to_s, 'config', 'multi_cap.yml') end def internal_config_directory File.join(CapistranoMulticonfigParallel.root.to_s, 'capistrano_multiconfig_parallel', 'initializers') end def command_line_params [ { name: 'multi_debug', type: :boolean, description: 'if option is present and has value TRUE , will enable debugging of workers', default: default_config[:multi_debug] }, { name: 'multi_progress', type: :boolean, description: "if option is present and has value TRUE will first execute before any process \t same task but with option '--dry-run' in order to show progress of how many tasks \t are in total for that task and what is the progress of executing \t This will slow down the workers , because they will execute twice the same task.", default: default_config[:multi_progress] }, { name: 'multi_secvential', type: :boolean, description: "If parallel executing does not work for you, you can use this option so that \t each process is executed normally and ouputted to the screen. \t However this means that all other tasks will have to wait for each other to finish before starting ", default: default_config[:multi_secvential] }, { name: 'websocket_server.enable_debug', type: :boolean, description: "if option is present and has value TRUE \t will enable debugging of websocket communication between the workers", default: default_config[:websocket_server][:enable_debug] }, { name: 'development_stages', type: Array, description: "if option is present and has value an ARRAY of STRINGS, \t each of them will be used as a development stage", default: default_config[:development_stages] }, { name: 'task_confirmations', type: Array, description: "if option is present and has value TRUE, will enable user confirmation dialogs \t before executing each task from option **--task_confirmations**", default: default_config[:task_confirmations] }, { name: 'task_confirmation_active', type: :boolean, description: "if option is present and has value an ARRAY of Strings, and --task_confirmation_active is TRUE , \t then will require a confirmation from user before executing the task. \t This will syncronize all workers to wait before executing that task, then a confirmation will be displayed, \t and when user will confirm , all workers will resume their operation", default: default_config[:task_confirmation_active] }, { name: 'syncronize_confirmation', type: :boolean, description: "if option is present and has value TRUE, all workers will be synchronized to wait for same task \t from the ***task_confirmations** Array before they execute it ", default: default_config[:syncronize_confirmation] }, { name: 'apply_stage_confirmation', type: Array, description: "if option is present and has value TRUE, all workers will be synchronized to wait for same task \t from the ***task_confirmations** Array before they execute it ", default: default_config[:apply_stage_confirmation] }, { name: 'track_dependencies', type: :boolean, description: "This should be useed only for Caphub-like applications , \t in order to deploy dependencies of an application in parallel. \t This is used only in combination with option **--application_dependencies** which is described \t at section **[2.) Multiple applications](#multiple_apps)**", default: default_config[:track_dependencies] }, { name: 'application_dependencies', type: Array, description: "This is an array of hashes. Each hash has only the keys \t 'app' ( app name), 'priority' and 'dependencies' \t ( an array of app names that this app is dependent to) ", default: default_config[:application_dependencies] } ] end def capistrano_options command_line_params.map do |param| [ "--#{param[:name]}[=CAP_VALUE]", "--#{param[:name]}", "[MULTI_CAP] #{param[:description]}", lambda do |_value| end ] end end def verify_array_of_strings(c, prop) value = c[prop] return unless value.present? value.reject(&:blank?) raise ArgumentError, 'the array must contain only task names' if value.find { |row| !row.is_a?(String) } end def verify_application_dependencies(value) value.reject { |val| val.blank? || !val.is_a?(Hash) } wrong = value.find do|hash| !Set[:app, :priority, :dependencies].subset?(hash.keys.to_set) || hash[:app].blank? || hash[:priority].blank? !hash[:priority].is_a?(Numeric) || !hash[:dependencies].is_a?(Array) end raise ArgumentError, "invalid configuration for #{wrong.inspect}" if wrong.present? end def check_boolean(c, prop) # return unless c[prop].present? raise ArgumentError, "the property `#{prop}` must be boolean" unless [true, false, 'true', 'false'].include?(c[prop].to_s.downcase) end def configuration_valid? configuration end def check_configuration(c) %w(multi_debug multi_progress multi_secvential task_confirmation_active track_dependencies websocket_server.enable_debug syncronize_confirmation).each do |prop| c.send("#{prop}=", c[prop.to_sym]) if check_boolean(c, prop.to_sym) end %w(task_confirmations development_stages apply_stage_confirmation).each do |prop| c.send("#{prop}=", c[prop.to_sym]) if verify_array_of_strings(c, prop.to_sym) end c.application_dependencies = c[:application_dependencies] if c[:track_dependencies].to_s.downcase == 'true' && verify_application_dependencies(c[:application_dependencies]) check_additional_config(c) end def check_additional_config(c) CapistranoMulticonfigParallel::CelluloidManager.debug_enabled = true if c[:multi_debug].to_s.downcase == 'true' CapistranoMulticonfigParallel.show_task_progress = true if c[:multi_progress].to_s.downcase == 'true' CapistranoMulticonfigParallel.execute_in_sequence = true if c[:multi_secvential].to_s.downcase == 'true' end end end end