class CapistranoMulticonfigParallel::Application

finds app dependencies, shows menu and delegates jobs to celluloid manager

Attributes

application[R]
args[R]
argv[R]
bundler_workers_store[R]
checked_job_paths[R]
condition[R]
default_stage[R]
dependency_tracker[R]
jobs[R]
manager[R]
name[R]
patched_job_paths[RW]
stage[R]
stage_apps[R]
top_level_tasks[R]

Public Class Methods

new() click to toggle source
# File lib/capistrano_multiconfig_parallel/application.rb, line 25
def initialize
  celluloid_running = Celluloid.running? rescue false
  Celluloid.boot unless celluloid_running
  CapistranoMulticonfigParallel.enable_logging
  @stage_apps = multi_apps? ? app_names_from_stages : []
  collect_command_line_tasks(CapistranoMulticonfigParallel.original_args)
  @bundler_workers_store = {}
  @jobs = []
  @checked_job_paths = []
  @patched_job_paths = [] # for deploy
end

Public Instance Methods

action_key() click to toggle source
# File lib/capistrano_multiconfig_parallel/application.rb, line 108
def action_key
  'ACTION'
end
add_job_to_list_of_jobs(job) click to toggle source
# File lib/capistrano_multiconfig_parallel/application.rb, line 240
def add_job_to_list_of_jobs(job)
  @jobs << job unless job_can_tag_staging?(job)
end
boxes_key() click to toggle source
# File lib/capistrano_multiconfig_parallel/application.rb, line 201
def boxes_key
  'BOX'
end
call_task_deploy_app(options = {}) click to toggle source
# File lib/capistrano_multiconfig_parallel/application.rb, line 205
def call_task_deploy_app(options = {})
  options = options.stringify_keys
  main_box_name = @argv[boxes_key].blank? ? '' : @argv[boxes_key]
  boxes = strip_characters_from_string(main_box_name).split(',').compact
  stage = options.fetch('stage', @default_stage)
  if configuration.development_stages.include?(stage) && boxes.present?
    execute_on_multiple_boxes(boxes, options)
  else
    prepare_job(options)
  end
end
can_tag_staging?() click to toggle source
# File lib/capistrano_multiconfig_parallel/application.rb, line 161
def can_tag_staging?
  wants_deploy_production? && fetch_multi_stages.include?('staging')
end
check_before_starting() click to toggle source
# File lib/capistrano_multiconfig_parallel/application.rb, line 117
def check_before_starting
  @dependency_tracker = CapistranoMulticonfigParallel::DependencyTracker.new(self)
  @default_stage = configuration.development_stages.present? ? configuration.development_stages.first : 'development'
  @condition = Celluloid::Condition.new
  @manager = CapistranoMulticonfigParallel::CelluloidManager.new(self)
  @manager.start_bundler_supervision_if_needed
end
collect_jobs(options = {}, &_block) click to toggle source
# File lib/capistrano_multiconfig_parallel/application.rb, line 125
def collect_jobs(options = {}, &_block)
  options = prepare_options(options)
  options = options.stringify_keys
  apps, app_options = @dependency_tracker.fetch_apps_needed_for_deployment(options['app'], options['action'])
  deploy_multiple_apps(apps, options)
  deploy_app(options.merge(app_options)) if !custom_command? || !multi_apps?
end
custom_command?() click to toggle source
# File lib/capistrano_multiconfig_parallel/application.rb, line 68
def custom_command?
  custom_commands.include?(@top_level_tasks.first)
end
deploy_app(options = {}) click to toggle source
# File lib/capistrano_multiconfig_parallel/application.rb, line 165
def deploy_app(options = {})
  options = options.stringify_keys
  call_task_deploy_app({
    app: options['app'],
    action: options['action']
  }.reverse_merge(options))
end
deploy_multiple_apps(applications, options) click to toggle source
# File lib/capistrano_multiconfig_parallel/application.rb, line 60
def deploy_multiple_apps(applications, options)
  options = options.stringify_keys
  return unless applications.present?
  applications.each do |app|
    deploy_app(options.merge('app' => app['app'], 'path' => app.fetch('path', nil)))
  end
end
execute_on_multiple_boxes(boxes, options) click to toggle source
# File lib/capistrano_multiconfig_parallel/application.rb, line 316
def execute_on_multiple_boxes(boxes, options)
  boxes.each do |box_name|
    options['env_options'][boxes_key] = box_name
    prepare_job(options)
  end
end
fetch_app_additional_env_options(variable) click to toggle source
# File lib/capistrano_multiconfig_parallel/application.rb, line 306
def fetch_app_additional_env_options(variable)
  options = {}
  return options if variable.blank?
  env_options = strip_characters_from_string(variable)
  env_options = env_options.split(' ')
  options = multi_fetch_argv(env_options)
  options.stringify_keys!
  options
end
fetch_multi_stages() click to toggle source
# File lib/capistrano_multiconfig_parallel/application.rb, line 150
def fetch_multi_stages
  custom_stages = @argv[stages_key].blank? ? '' : @argv[stages_key]
  custom_stages = strip_characters_from_string(custom_stages).split(',').compact if custom_stages.present?
  custom_stages = custom_stages.present? ? custom_stages : [@default_stage]
  custom_stages
end
get_app_additional_env_options(app, app_message) click to toggle source
# File lib/capistrano_multiconfig_parallel/application.rb, line 173
def get_app_additional_env_options(app, app_message)
  app_name = (app.is_a?(Hash) && app[:app].present?) ? app[:app].camelcase : app
  app_name = app_name.present? ? app_name : 'current application'
  message = "Please write additional ENV options for #{app_name} for #{app_message}"
  app_additional_env_options = ask_confirm(message, nil)
  fetch_app_additional_env_options(app_additional_env_options)
end
initialize_data() click to toggle source
# File lib/capistrano_multiconfig_parallel/application.rb, line 88
def initialize_data
  @application = custom_command? ? nil : @top_level_tasks.first.split(':').reverse[1]
  @stage = custom_command? ? nil : @top_level_tasks.first.split(':').reverse[0]
  @stage = @stage.present? ? @stage : @default_stage
  @name, @args = parse_task_string(@top_level_tasks[1])
end
job_can_tag_staging?(job) click to toggle source
# File lib/capistrano_multiconfig_parallel/application.rb, line 278
def job_can_tag_staging?(job)
  can_tag_staging? && job.stage == 'production' && job.gitflow.present?
end
job_path(options) click to toggle source
# File lib/capistrano_multiconfig_parallel/application.rb, line 282
def job_path(options)
  path = options["path"].present? ? options["path"] : nil
  path.present? && File.directory?(path) ? path : detect_root
end
job_stage(options) click to toggle source
# File lib/capistrano_multiconfig_parallel/application.rb, line 291
def job_stage(options)
  options['stage']
end
job_stage_valid?(options) click to toggle source
# File lib/capistrano_multiconfig_parallel/application.rb, line 287
def job_stage_valid?(options)
  stages(job_path(options)).include?(job_stage(options))
end
jobs_restore_application_state() click to toggle source
# File lib/capistrano_multiconfig_parallel/application.rb, line 322
def jobs_restore_application_state
  @jobs.each do |job|
    job.rollback_changes_to_application
  end
end
prepare_job(options) click to toggle source
# File lib/capistrano_multiconfig_parallel/application.rb, line 244
def prepare_job(options)
  options = options.stringify_keys
  app = options.fetch('app', '')
  path = job_path(options) rescue nil
#  raise [app, @stage_apps, job_stage(options) , stages(job_path(options))].inspect
  return raise_invalid_job_config(path) if (app.present? && !@stage_apps.include?(app)) || !job_stage_valid?(options)
  app = options.fetch('app', '')
  box = options['env_options'][boxes_key]
  message = box.present? ? "BOX #{box}:" : "stage #{options['stage']}:"
  env_opts = get_app_additional_env_options(app, message)

  options['env_options'] = options['env_options'].reverse_merge(env_opts)

  env_options = options['env_options']
  job_env_options = custom_command? ? env_options.except(action_key) : env_options

  job = CapistranoMulticonfigParallel::Job.new(self, options.merge(
  action: custom_command? && env_options[action_key].present? ? env_options[action_key] : options['action'],
  env_options: job_env_options,
  path:  job_path(options)

  ))

  if configuration.check_app_bundler_dependencies.to_s.downcase == 'true' && job.job_gemfile.present?
    if !@checked_job_paths.include?(job.job_path)
      @checked_job_paths << job.job_path
      @manager.bundler_workers.work(job) # make sure we have installed the dependencies first for this application
    end
  else
    add_job_to_list_of_jobs(job)
  end

end
prepare_options(options) click to toggle source
# File lib/capistrano_multiconfig_parallel/application.rb, line 296
def prepare_options(options)
  options = options.stringify_keys
  options['app'] = options.fetch('app', @application.to_s.clone)
  options['action'] = options.fetch('action', @name.to_s.clone)
  options['stage'] = options.fetch('stage', @stage.to_s.clone)
  options['env_options'] = options.fetch('env_options', @argv.clone)
  options['task_arguments'] = options.fetch('task_arguments', @args.clone)
  options
end
process_jobs() click to toggle source
# File lib/capistrano_multiconfig_parallel/application.rb, line 133
def process_jobs
  return unless @jobs.present?
  if configuration.multi_secvential.to_s.downcase == 'true'
    @jobs.each(&:execute_standard_deploy)
  else
    run_async_jobs
  end
end
raise_invalid_job_config(path = nil) click to toggle source
# File lib/capistrano_multiconfig_parallel/application.rb, line 77
def raise_invalid_job_config(path = nil)
  if independent_deploy?(path)
      puts 'Invalid execution, please call something such as `multi_cap app_name:production deploy`, where production is a stage you have defined and the "app_name" is a name that you defined in your multi_cap.yml file'.red
  elsif application_supports_multi_apps?
    puts 'Invalid execution, please call something such as `multi_cap app_name:production deploy`, where production is a stage you have defined and the "app_name" is name that you have defined in your application'.red
  else
    puts 'Invalid execution, please call something such as `multi_cap production deploy`, where production is a stage you have defined'.red
  end
  exit(false)
end
run() click to toggle source
# File lib/capistrano_multiconfig_parallel/application.rb, line 181
def run
  FileUtils.rm Dir["#{log_directory}/worker_*.log"]
  FileUtils.rm Dir["#{log_directory}/multi_cap_worker_*.log"]
  options = {}
  if custom_command?
    options = verify_options_custom_command(options)
    run_custom_command(options)
  else
    collect_jobs(options)
  end
  if configuration.check_app_bundler_dependencies.to_s.downcase == 'true'
    loop do
      log_to_file("Trying to sleep until all budler workes are done (#{@jobs.size} and #{@bundler_workers_store.size})")
      break if @jobs.size == @bundler_workers_store.size
      sleep(0.1)
    end
  end
  process_jobs
end
run_async_jobs() click to toggle source
# File lib/capistrano_multiconfig_parallel/application.rb, line 217
def run_async_jobs
  return unless @jobs.present?
  @jobs.pmap do |job|
    @manager.async.delegate_job(job)
  end
  unless can_tag_staging? && tag_staging_exists?
    until @manager.registration_complete
      sleep(0.1) # keep current thread alive
    end
    return unless @manager.registration_complete
    @manager.async.process_jobs
  end
  wait_jobs_termination
end
run_custom_command(options) click to toggle source
# File lib/capistrano_multiconfig_parallel/application.rb, line 52
def run_custom_command(options)
  custom_stages = fetch_multi_stages
  return if custom_stages.blank?
  custom_stages.each do |stage|
    collect_jobs(options.merge('stage' => stage))
  end
end
stages_key() click to toggle source
# File lib/capistrano_multiconfig_parallel/application.rb, line 146
def stages_key
  'STAGES'
end
start() click to toggle source
# File lib/capistrano_multiconfig_parallel/application.rb, line 37
def start
  verify_app_dependencies if multi_apps? && configuration.application_dependencies.present?
  initialize_data
  verify_valid_data
  check_before_starting
  run
end
tag_staging_exists?() click to toggle source
# File lib/capistrano_multiconfig_parallel/application.rb, line 142
def tag_staging_exists? # check exists task from capistrano-gitflow
  @jobs.find(&:gitflow).present?
end
verify_app_dependencies() click to toggle source
# File lib/capistrano_multiconfig_parallel/application.rb, line 45
def verify_app_dependencies
  wrong = configuration.application_dependencies.find do |hash|
    !@stage_apps.include?(hash[:app]) || (hash[:dependencies].present? && hash[:dependencies].find { |val| !@stage_apps.include?(val) })
  end
  raise ArgumentError, "Invalid configuration for #{wrong.inspect}".red if wrong.present?
end
verify_options_custom_command(options) click to toggle source
# File lib/capistrano_multiconfig_parallel/application.rb, line 112
def verify_options_custom_command(options)
  options[:action] = @argv[action_key].present? ? @argv[action_key] : 'deploy'
  options
end
verify_valid_data() click to toggle source
# File lib/capistrano_multiconfig_parallel/application.rb, line 72
def verify_valid_data
  return if  @top_level_tasks != ['default']
  raise_invalid_job_config
end
wait_jobs_termination() click to toggle source
# File lib/capistrano_multiconfig_parallel/application.rb, line 232
def wait_jobs_termination
  return if configuration.multi_secvential.to_s.downcase == 'true'
  result = @condition.wait
  return unless result.present?
  @manager.terminate
  #terminate
end
wants_deploy_production?() click to toggle source
# File lib/capistrano_multiconfig_parallel/application.rb, line 157
def wants_deploy_production?
  (!custom_command? && @stage == 'production') || (custom_command? && fetch_multi_stages.include?('production'))
end