class EcoRake module Lib module People # @todo on_error_email to ensure always notified # @todo ping some back-end that it was run # - Should be able to log at debug level. class SyncLaunch < EcoRake::Lib::People::BaseTask ADDITIONAL_OPTIONS = %i[only_stats no_policy simulate].freeze FORWARD_RULES = { schema: ->(schema) { "-schema-id \"#{schema}\"" }, only_stats: '-feed-only-stats', no_policy: '-skip-batch-policy', simulate: '-simulate' }.freeze attr_const :target_enviro, required: true option_reopen :enviro, default_lookup: :target_enviro attr_const :base_usecase, :default_schema, :file_pattern, required: true attr_const :snapshot_mode, default: :full attr_const :local_folder, default: '.' attr_const :mail_to option_reopen :schema, default_lookup: :default_schema, required: true option_reopen :folder, default_lookup: :local_folder option_forwarding(**FORWARD_RULES) def task(*_args) return missing_files_notify unless latest_file return process_deltas if delta? return process_full_file if full? || delta_last? end private def process_full_file sh people_get_command unless options[:no_get] || delta_last? sh_continue sync_command(latest_file) clear_files unless options[:simulate] end def process_deltas target_files.each do |file| sh sync_command(file) next if options[:simulate] puts "Deleting file #{file}" File.delete(file) end end def missing_files_notify puts "Missing files to be processed" exit 1 if options[:simulate] exit 1 unless inbox = mail_to email_missing_files(enviro: target_enviro, to: inbox) exit 1 end # @yield [cmd] do something to extend the command # @yieldparam cmd [Array] the command as this task would generate it. # @yieldresult [Array] the final command # @return [String] the sync command def sync_command(file) cmd = [] cmd << ruby_runner cmd << forward_option(:enviro) cmd << forward_option(:schema) cmd << '-get-partial' if delta? || delta_last? cmd << base_command(file) cmd.concat(forward_options(*self.class::ADDITIONAL_OPTIONS)) cmd = yield(cmd) if block_given? string_cmd(*cmd) end # Generate command string to get people def people_get_command string_cmd(ruby_runner, forward_option(:enviro), '-get-people') end # Base command scoping. # @note it ensures basic information is not missing or inconsistent. def base_command(file_or_folder) raise "Missing target file or folder in #{self.class}" if file_or_folder.to_s.strip.empty? usecase = base_usecase.to_sym case usecase when :hris msg = "Inconsistent configuration in #{self.class}. BASE_USECASE is '#{usecase}', " msg << "but file SNAPSHOT_MODE is '#{snapshot_mode}'" raise msg if delta? || delta_last? "-hris-from #{double_quote(file_or_folder)}" when :upsert "-upsert-from #{double_quote(file_or_folder)}" else raise ArgumentError, "Unknown use case '#{usecase}'" end end def full? snapshot_mode.to_s.downcase.to_sym == :full end def delta? mode = snapshot_mode.to_s.downcase.to_sym %i[partial delta].any? {|m| m == mode} end def delta_last? snapshot_mode.to_s.downcase.to_sym == :delta_last end # Amont the `target_files` the last in alphabetic order. def latest_file @latest_file ||= target_files.last end # @note if there is a file_pattern method or FILE_PATTERN const, it's used as a pattern. # @return [Array] the `csv` files of the target folder def target_files @target_files ||= csv_files(options[:folder], regexp: file_pattern) end # Deletes the files identified as target. def clear_files deleted_files = target_files.each_with_object([]) do |file, deleted| next unless File.exist?(file) File.delete(file) deleted << file end puts "Deleted these files:\n • #{deleted_files.join("\n • ")}" unless deleted_files.empty? end end end end end