Class: Aspera::Cli::Runner
- Inherits:
-
Object
- Object
- Aspera::Cli::Runner
- Defined in:
- lib/aspera/cli/runner.rb
Overview
The main CLI class
Constant Summary collapse
- STATUS_FIELD =
Plugins store transfer result using this key and use result_transfer_multiple()
'status'
Instance Attribute Summary collapse
-
#context ⇒ Object
readonly
Returns the value of attribute context.
Class Method Summary collapse
-
.result_transfer(transfer_result) ⇒ Result
Process the typed result of a finished (or submitted) transfer.
-
.result_transfer_multiple(status_table) ⇒ Result
Used when one command executes several transfer jobs (each job being possibly multi session).
Instance Method Summary collapse
-
#initialize(argv) ⇒ nil
constructor
Minimum initialization, no exception raised.
-
#option_log(_option_sym, operation, value = nil) ⇒ Object
Composite option handler for the
logoption (dot-notation sub-properties). -
#result_usage(plugin: nil) ⇒ Result::Text
Return usage as a Result::Text (used by run_with_result, no display, no exit).
-
#run ⇒ nil
Main entry point: execute the command, display results, exit on error.
-
#run_with_result ⇒ Result?
Execute the command and return the raw
Resultobject. -
#show_usage(plugin: nil) ⇒ nil
Display usage information and exit (used by the interactive CLI).
Constructor Details
Instance Attribute Details
#context ⇒ Object (readonly)
Returns the value of attribute context.
87 88 89 |
# File 'lib/aspera/cli/runner.rb', line 87 def context @context end |
Class Method Details
.result_transfer(transfer_result) ⇒ Result
Process the typed result of a finished (or submitted) transfer.
39 40 41 42 43 44 45 46 47 48 49 50 |
# File 'lib/aspera/cli/runner.rb', line 39 def result_transfer(transfer_result) case transfer_result when Transfer::Result::Async return Result::SingleObject.new(transfer_result.to_h) when Transfer::Result::Error raise transfer_result.exception when Transfer::Result::Success return Result::Nothing.new else raise "Unexpected transfer result type: #{transfer_result.class}" end end |
.result_transfer_multiple(status_table) ⇒ Result
Used when one command executes several transfer jobs (each job being possibly multi session)
55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 |
# File 'lib/aspera/cli/runner.rb', line 55 def result_transfer_multiple(status_table) failed_result = nil status_table.each do |item| tr = item[STATUS_FIELD] case tr when Transfer::Result::Error failed_result ||= tr item[STATUS_FIELD] = tr.exception. when Transfer::Result::Success item[STATUS_FIELD] = 'success' when Transfer::Result::Async item[STATUS_FIELD] = "async:#{tr.job_id}" else item[STATUS_FIELD] = tr.to_s end end raise failed_result.exception unless failed_result.nil? return Result::ObjectList.new(status_table) end |
Instance Method Details
#option_log(_option_sym, operation, value = nil) ⇒ Object
Composite option handler for the log option (dot-notation sub-properties).
Supported sub-properties: level, type, format
228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 |
# File 'lib/aspera/cli/runner.rb', line 228 def option_log(_option_sym, operation, value = nil) Aspera.assert_values(operation, %i[set get]) case operation when :set Aspera.assert_type(value, Hash) value.each do |k, v| case k.to_sym when :level then Log.instance.level = v.to_sym when :type then Log.instance.logger_type = v.to_sym when :format then Log.instance.formatter = v when :secrets then SecretHider.instance.log_secrets = BoolValue.true?(v) else Aspera.error_unexpected_value(k){'log sub-option (level, type, format, secrets)'} end end when :get return {level: Log.instance.level, type: Log.instance.logger_type, format: Log.instance.formatter, secrets: SecretHider.instance.log_secrets} end nil end |
#result_usage(plugin: nil) ⇒ Result::Text
Return usage as a Result::Text (used by run_with_result, no display, no exit).
219 220 221 |
# File 'lib/aspera/cli/runner.rb', line 219 def result_usage(plugin: nil) Result::Text.new(usage_text(plugin: plugin)) end |
#run ⇒ nil
Main entry point: execute the command, display results, exit on error.
156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 |
# File 'lib/aspera/cli/runner.rb', line 156 def run exception_info = nil begin result = run_with_result @context.formatter.display_results(result) if result rescue Net::SSH::AuthenticationFailed => e; exception_info = {e: e, t: 'SSH', security: true} rescue OpenSSL::SSL::SSLError => e; exception_info = {e: e, t: 'SSL'} rescue Cli::BadArgument => e; exception_info = {e: e, t: 'Argument', usage: true} rescue Cli::MissingArgument => e; exception_info = {e: e, t: 'Missing'} rescue Cli::BadIdentifier => e; exception_info = {e: e, t: 'Identifier'} rescue Cli::SchemaRequest => e; exception_info = {e: e, t: 'Schema'} rescue Cli::Error => e; exception_info = {e: e, t: 'Tool', usage: true} rescue Transfer::Error => e; exception_info = {e: e, t: 'Transfer'} rescue RestCallError => e; exception_info = {e: e, t: 'Rest'} rescue SocketError => e; exception_info = {e: e, t: 'Network'} rescue StandardError => e; exception_info = {e: e, t: "Other(#{e.class.name})", debug: true} rescue Interrupt => e; exception_info = {e: e, t: 'Interruption', debug: true} end # 1- processing of error condition unless exception_info.nil? Log.log.warn(exception_info[:e].) if Log.instance.logger_type.eql?(:syslog) && exception_info[:security] Log.log.error{"#{exception_info[:t]}: #{exception_info[:e].}"} unless exception_info[:e].is_a?(Cli::SchemaRequest) Log.log.debug{(['Backtrace:'] + exception_info[:e].backtrace).join("\n")} if exception_info[:debug] @context.formatter.(:error, 'Use option -h to get help.') if exception_info[:usage] Hints.hint_for(exception_info[:e], @context.formatter) if exception_info[:e].is_a?(Cli::SchemaRequest) Log.log.info{"#{exception_info[:t]}: #{exception_info[:e].}"} schema_path = exception_info[:e].path if schema_path.nil? Log.log.warn{'Sorry, no schema provided yet. Please refer to the manual or API.'} else builder = Schema::Documentation.new(TerminalFormatter, Schema::Registry.instance.reader(schema_path)).build @context.formatter.display_results(Result::ObjectList.new(builder.rows, fields: builder.columns)) end end end # 2- processing of unprocessed arguments (skip when help was displayed: sub-commands are not consumed) unless @option_help @context.&.final_errors&.each do |msg| Log.log.error{"Argument: #{msg}"} exception_info = {e: Exception.new(msg), t: 'UnusedArg'} if exception_info.nil? end end # 3- exit on error unless exception_info.nil? raise exception_info[:e] if Log.log.debug? @context.formatter.(:error, 'Use --log-level=debug to get more details.') if exception_info[:debug] Process.exit(1) end return end |
#run_with_result ⇒ Result?
Execute the command and return the raw Result object.
Pure computation: no display, no Process.exit - raises on any error.
92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 |
# File 'lib/aspera/cli/runner.rb', line 92 def run_with_result Plugins::Factory.instance.add_plugins_from_lookup_folders # Help requested without command? Show global options + plugin list return result_usage if @option_help && @context..command_or_arg_empty? @context.config.periodic_check_newer_gem_version command_sym = if @option_show_config && @context..command_or_arg_empty? COMMAND_CONFIG else @context..get_next_command(Plugins::Factory.instance.plugin_list.unshift(COMMAND_HELP)) end @context..fail_on_missing_mandatory = false if @option_help || @option_show_config case command_sym when COMMAND_HELP return result_usage when COMMAND_CONFIG command_plugin = @context.config else command_plugin = (command_sym) @context.. end # --help after a plugin name: if no positional args remain, show plugin-level help now. # If args remain (e.g. `ascli aoc files -h`), let the dispatch consume them and # intercept --help at the right depth via Cli::HelpRequest. return result_usage(plugin: command_plugin) if @option_help && @context..command_or_arg_empty? if @option_show_config result = Result::SingleObject.new(@context..(only_defined: true).stringify_keys) @context.presets.save_if_needed @context.transfer.shutdown TempFileManager.instance.cleanup return result end execute_command = true lock_port = @context..get_option(:lock_port) if !lock_port.nil? begin Log.log.debug{"Opening lock port #{lock_port}"} @tcp_server = TCPServer.new('127.0.0.1', lock_port) rescue StandardError => e execute_command = false Log.log.warn{"Another instance is already running (#{e.})."} end end pid_file = @context..get_option(:pid_file) if !pid_file.nil? File.write(pid_file, Process.pid) Log.log.debug{"Wrote pid #{Process.pid} to #{pid_file}"} at_exit{File.delete(pid_file)} end begin result = command_plugin.execute_action if execute_command rescue Cli::HelpRequest => e return result_usage(plugin: e.plugin) ensure @context.presets.save_if_needed @context.transfer.shutdown TempFileManager.instance.cleanup end return result end |
#show_usage(plugin: nil) ⇒ nil
Display usage information and exit (used by the interactive CLI).
211 212 213 214 |
# File 'lib/aspera/cli/runner.rb', line 211 def show_usage(plugin: nil) @context.formatter.(:error, usage_text(plugin: plugin)) Process.exit(0) end |