aspera-cli 4.6.0 → 4.7.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (96) hide show
  1. checksums.yaml +4 -4
  2. data/README.md +427 -300
  3. data/bin/ascli +2 -1
  4. data/bin/asession +1 -0
  5. data/docs/test_env.conf +2 -0
  6. data/examples/aoc.rb +4 -3
  7. data/examples/faspex4.rb +21 -19
  8. data/examples/proxy.pac +1 -1
  9. data/examples/transfer.rb +15 -15
  10. data/lib/aspera/aoc.rb +135 -124
  11. data/lib/aspera/ascmd.rb +85 -75
  12. data/lib/aspera/ats_api.rb +11 -10
  13. data/lib/aspera/cli/basic_auth_plugin.rb +13 -14
  14. data/lib/aspera/cli/extended_value.rb +42 -33
  15. data/lib/aspera/cli/formater.rb +138 -111
  16. data/lib/aspera/cli/info.rb +17 -0
  17. data/lib/aspera/cli/listener/line_dump.rb +3 -2
  18. data/lib/aspera/cli/listener/logger.rb +2 -1
  19. data/lib/aspera/cli/listener/progress.rb +16 -18
  20. data/lib/aspera/cli/listener/progress_multi.rb +13 -16
  21. data/lib/aspera/cli/main.rb +122 -130
  22. data/lib/aspera/cli/manager.rb +146 -154
  23. data/lib/aspera/cli/plugin.rb +38 -34
  24. data/lib/aspera/cli/plugins/alee.rb +6 -6
  25. data/lib/aspera/cli/plugins/aoc.rb +273 -276
  26. data/lib/aspera/cli/plugins/ats.rb +82 -76
  27. data/lib/aspera/cli/plugins/bss.rb +14 -16
  28. data/lib/aspera/cli/plugins/config.rb +350 -306
  29. data/lib/aspera/cli/plugins/console.rb +23 -19
  30. data/lib/aspera/cli/plugins/cos.rb +18 -18
  31. data/lib/aspera/cli/plugins/faspex.rb +180 -159
  32. data/lib/aspera/cli/plugins/faspex5.rb +64 -54
  33. data/lib/aspera/cli/plugins/node.rb +147 -140
  34. data/lib/aspera/cli/plugins/orchestrator.rb +68 -66
  35. data/lib/aspera/cli/plugins/preview.rb +92 -96
  36. data/lib/aspera/cli/plugins/server.rb +79 -75
  37. data/lib/aspera/cli/plugins/shares.rb +23 -24
  38. data/lib/aspera/cli/plugins/sync.rb +20 -22
  39. data/lib/aspera/cli/transfer_agent.rb +40 -39
  40. data/lib/aspera/cli/version.rb +2 -1
  41. data/lib/aspera/colors.rb +35 -27
  42. data/lib/aspera/command_line_builder.rb +48 -34
  43. data/lib/aspera/cos_node.rb +29 -21
  44. data/lib/aspera/data_repository.rb +3 -2
  45. data/lib/aspera/environment.rb +50 -45
  46. data/lib/aspera/fasp/agent_base.rb +22 -20
  47. data/lib/aspera/fasp/agent_connect.rb +13 -11
  48. data/lib/aspera/fasp/agent_direct.rb +48 -59
  49. data/lib/aspera/fasp/agent_httpgw.rb +33 -39
  50. data/lib/aspera/fasp/agent_node.rb +15 -13
  51. data/lib/aspera/fasp/agent_trsdk.rb +12 -14
  52. data/lib/aspera/fasp/error.rb +2 -1
  53. data/lib/aspera/fasp/error_info.rb +68 -52
  54. data/lib/aspera/fasp/installation.rb +106 -94
  55. data/lib/aspera/fasp/listener.rb +1 -0
  56. data/lib/aspera/fasp/parameters.rb +83 -92
  57. data/lib/aspera/fasp/parameters.yaml +305 -249
  58. data/lib/aspera/fasp/resume_policy.rb +11 -14
  59. data/lib/aspera/fasp/transfer_spec.rb +26 -0
  60. data/lib/aspera/fasp/uri.rb +22 -21
  61. data/lib/aspera/faspex_gw.rb +55 -90
  62. data/lib/aspera/hash_ext.rb +4 -3
  63. data/lib/aspera/id_generator.rb +8 -7
  64. data/lib/aspera/keychain/encrypted_hash.rb +17 -16
  65. data/lib/aspera/keychain/macos_security.rb +6 -10
  66. data/lib/aspera/log.rb +25 -20
  67. data/lib/aspera/nagios.rb +13 -12
  68. data/lib/aspera/node.rb +30 -22
  69. data/lib/aspera/oauth.rb +175 -226
  70. data/lib/aspera/open_application.rb +4 -3
  71. data/lib/aspera/persistency_action_once.rb +6 -6
  72. data/lib/aspera/persistency_folder.rb +5 -9
  73. data/lib/aspera/preview/file_types.rb +6 -5
  74. data/lib/aspera/preview/generator.rb +25 -24
  75. data/lib/aspera/preview/options.rb +16 -14
  76. data/lib/aspera/preview/utils.rb +98 -98
  77. data/lib/aspera/{proxy_auto_config.erb.js → proxy_auto_config.js} +23 -31
  78. data/lib/aspera/proxy_auto_config.rb +111 -20
  79. data/lib/aspera/rest.rb +115 -113
  80. data/lib/aspera/rest_call_error.rb +2 -2
  81. data/lib/aspera/rest_error_analyzer.rb +23 -25
  82. data/lib/aspera/rest_errors_aspera.rb +15 -14
  83. data/lib/aspera/ssh.rb +12 -10
  84. data/lib/aspera/sync.rb +42 -41
  85. data/lib/aspera/temp_file_manager.rb +18 -14
  86. data/lib/aspera/timer_limiter.rb +2 -1
  87. data/lib/aspera/uri_reader.rb +7 -5
  88. data/lib/aspera/web_auth.rb +79 -76
  89. metadata +64 -21
  90. data/docs/Makefile +0 -65
  91. data/docs/README.erb.md +0 -4424
  92. data/docs/README.md +0 -13
  93. data/docs/diagrams.txt +0 -49
  94. data/docs/doc_tools.rb +0 -58
  95. data/lib/aspera/cli/plugins/shares2.rb +0 -114
  96. data/lib/aspera/fasp/default.rb +0 -17
@@ -1,3 +1,4 @@
1
+ # frozen_string_literal: true
1
2
  require 'aspera/colors'
2
3
  require 'aspera/log'
3
4
  require 'aspera/cli/extended_value'
@@ -29,11 +30,11 @@ module Aspera
29
30
  end
30
31
 
31
32
  def value
32
- @object.send(@attr_symb.to_s)
33
+ return @object.send(@attr_symb)
33
34
  end
34
35
 
35
36
  def value=(val)
36
- @object.send(@attr_symb.to_s+'=',val)
37
+ @object.send("#{@attr_symb}=",val)
37
38
  end
38
39
  end
39
40
 
@@ -41,14 +42,10 @@ module Aspera
41
42
  # arguments options start with '-', others are commands
42
43
  # resolves on extended value syntax
43
44
  class Manager
44
- def self.time_to_string(time)
45
- time.strftime("%Y-%m-%d %H:%M:%S")
46
- end
47
-
48
45
  # boolean options are set to true/false from the following values
49
- TRUE_VALUES=[:yes,true]
50
- BOOLEAN_VALUES=TRUE_VALUES.clone.push(:no,false)
51
- BOOLEAN_SIMPLE=[:yes,:no]
46
+ TRUE_VALUES=[:yes,true].freeze
47
+ BOOLEAN_VALUES=[TRUE_VALUES,:no,false].flatten.freeze
48
+ BOOLEAN_SIMPLE=[:yes,:no].freeze
52
49
  # option name separator on command line
53
50
  OPTION_SEP_LINE='-'
54
51
  # option name separator in code (symbol)
@@ -56,30 +53,37 @@ module Aspera
56
53
 
57
54
  private_constant :TRUE_VALUES,:BOOLEAN_VALUES,:BOOLEAN_SIMPLE,:OPTION_SEP_LINE,:OPTION_SEP_NAME
58
55
 
59
- def enum_to_bool(enum);TRUE_VALUES.include?(enum);end
60
-
61
- # find shortened string value in allowed symbol list
62
- def self.get_from_list(shortval,descr,allowed_values)
63
- # we accept shortcuts
64
- matching_exact=allowed_values.select{|i| i.to_s.eql?(shortval)}
65
- return matching_exact.first if matching_exact.length == 1
66
- matching=allowed_values.select{|i| i.to_s.start_with?(shortval)}
67
- raise cli_bad_arg("unknown value for #{descr}: #{shortval}",allowed_values) if matching.empty?
68
- raise cli_bad_arg("ambigous shortcut for #{descr}: #{shortval}",matching) unless matching.length.eql?(1)
69
- return enum_to_bool(matching.first) if allowed_values.eql?(BOOLEAN_VALUES)
70
- return matching.first
71
- end
56
+ class << self
57
+ def enum_to_bool(enum)
58
+ raise "Value not valid for boolean: #{enum}/#{enum.class}" unless BOOLEAN_VALUES.include?(enum)
59
+ return TRUE_VALUES.include?(enum)
60
+ end
61
+
62
+ def time_to_string(time)
63
+ return time.strftime('%Y-%m-%d %H:%M:%S')
64
+ end
65
+
66
+ # find shortened string value in allowed symbol list
67
+ def get_from_list(shortval,descr,allowed_values)
68
+ # we accept shortcuts
69
+ matching_exact=allowed_values.select{|i| i.to_s.eql?(shortval)}
70
+ return matching_exact.first if matching_exact.length == 1
71
+ matching=allowed_values.select{|i| i.to_s.start_with?(shortval)}
72
+ raise CliBadArgument,bad_arg_message_multi("unknown value for #{descr}: #{shortval}",allowed_values) if matching.empty?
73
+ raise CliBadArgument,bad_arg_message_multi("ambigous shortcut for #{descr}: #{shortval}",matching) unless matching.length.eql?(1)
74
+ return enum_to_bool(matching.first) if allowed_values.eql?(BOOLEAN_VALUES)
75
+ return matching.first
76
+ end
72
77
 
73
- def self.cli_bad_arg(error_msg,choices)
74
- return CliBadArgument.new(error_msg+"\nUse:\n"+choices.map{|c| "- #{c.to_s}\n"}.sort.join(''))
78
+ def bad_arg_message_multi(error_msg,choices)
79
+ return [error_msg,'Use:',choices.map{|c|"- #{c}"}.sort].flatten.join("\n")
80
+ end
75
81
  end
76
82
 
77
83
  attr_reader :parser
78
- attr_accessor :ask_missing_mandatory
79
- attr_accessor :ask_missing_optional
84
+ attr_accessor :ask_missing_mandatory, :ask_missing_optional
80
85
  attr_writer :fail_on_missing_mandatory
81
86
 
82
- #
83
87
  def initialize(program_name,argv=nil)
84
88
  # command line values not starting with '-'
85
89
  @unprocessed_cmd_line_arguments=[]
@@ -114,15 +118,15 @@ module Aspera
114
118
  unless argv.nil?
115
119
  @parser.separator('')
116
120
  @parser.separator('OPTIONS: global')
117
- self.set_obj_attr(:interactive,self,:ask_missing_mandatory)
118
- self.set_obj_attr(:ask_options,self,:ask_missing_optional)
119
- self.add_opt_boolean(:interactive,'use interactive input of missing params')
120
- self.add_opt_boolean(:ask_options,'ask even optional options')
121
- self.parse_options!
121
+ set_obj_attr(:interactive,self,:ask_missing_mandatory)
122
+ set_obj_attr(:ask_options,self,:ask_missing_optional)
123
+ add_opt_boolean(:interactive,'use interactive input of missing params')
124
+ add_opt_boolean(:ask_options,'ask even optional options')
125
+ parse_options!
122
126
  process_options=true
123
127
  while !argv.empty?
124
128
  value=argv.shift
125
- if process_options and value.start_with?('-')
129
+ if process_options && value.start_with?('-')
126
130
  if value.eql?('--')
127
131
  process_options=false
128
132
  else
@@ -137,41 +141,6 @@ module Aspera
137
141
  Log.log.debug("add_cmd_line_options:commands/args=#{@unprocessed_cmd_line_arguments},options=#{@unprocessed_cmd_line_options}".red)
138
142
  end
139
143
 
140
- def prompt_user_input(prompt,sensitive)
141
- return STDIN.getpass("#{prompt}> ") if sensitive
142
- print "#{prompt}> "
143
- return STDIN.gets.chomp
144
- end
145
-
146
- def get_interactive(type,descr,expected=:single)
147
- if !@ask_missing_mandatory
148
- if expected.is_a?(Array)
149
- raise self.class.cli_bad_arg("missing: #{descr}",expected)
150
- end
151
- raise CliBadArgument,"missing argument (#{expected}): #{descr}"
152
- end
153
- result=nil
154
- # Note: mandatory parenthesis here !
155
- sensitive = (type.eql?(:option) and @declared_options[descr.to_sym][:sensitive].eql?(true))
156
- default_prompt="#{type}: #{descr}"
157
- # ask interactively
158
- case expected
159
- when :multiple
160
- result=[]
161
- puts " (one per line, end with empty line)"
162
- loop do
163
- entry=prompt_user_input(default_prompt,sensitive)
164
- break if entry.empty?
165
- result.push(ExtendedValue.instance.evaluate(entry))
166
- end
167
- when :single
168
- result=ExtendedValue.instance.evaluate(prompt_user_input(default_prompt,sensitive))
169
- else # one fixed
170
- result=self.class.get_from_list(prompt_user_input("#{expected.join(' ')}\n#{default_prompt}",sensitive),descr,expected)
171
- end
172
- return result
173
- end
174
-
175
144
  def get_next_command(command_list); return get_next_argument('command',command_list); end
176
145
 
177
146
  # @param expected is
@@ -190,17 +159,15 @@ module Aspera
190
159
  when :multiple
191
160
  result = @unprocessed_cmd_line_arguments.shift(@unprocessed_cmd_line_arguments.length).map{|v|ExtendedValue.instance.evaluate(v)}
192
161
  # if expecting list and only one arg of type array : it is the list
193
- if result.length.eql?(1) and result.first.is_a?(Array)
162
+ if result.length.eql?(1) && result.first.is_a?(Array)
194
163
  result=result.first
195
164
  end
196
165
  else
197
166
  result=self.class.get_from_list(@unprocessed_cmd_line_arguments.shift,descr,expected)
198
167
  end
199
- else
168
+ elsif is_type.eql?(:mandatory)
200
169
  # no value provided
201
- if is_type.eql?(:mandatory)
202
- result=get_interactive(:argument,descr,expected)
203
- end
170
+ result=get_interactive(:argument,descr,expected)
204
171
  end
205
172
  Log.log.debug("#{descr}=#{result}")
206
173
  return result
@@ -213,13 +180,9 @@ module Aspera
213
180
  raise "INTERNAL ERROR: option #{option_symbol} already declared. only accessor can be redeclared and ignored" unless @declared_options[option_symbol][:type].eql?(:accessor)
214
181
  return
215
182
  end
216
- @declared_options[option_symbol]={:type=>type}
183
+ @declared_options[option_symbol]={type: type}
217
184
  # by default passwords and secrets are sensitive, else specify when declaring the option
218
- set_is_sensitive(option_symbol) if !%w{password secret key}.select{|i| option_symbol.to_s.end_with?(i)}.empty?
219
- end
220
-
221
- def set_is_sensitive(option_symbol)
222
- @declared_options[option_symbol][:sensitive]=true
185
+ @declared_options[option_symbol][:sensitive]=true if !%w[password secret key].select{|i| option_symbol.to_s.end_with?(i)}.empty?
223
186
  end
224
187
 
225
188
  # define option with handler
@@ -227,29 +190,26 @@ module Aspera
227
190
  Log.log.debug("set attr obj #{option_symbol} (#{object},#{attr_symb})")
228
191
  declare_option(option_symbol,:accessor)
229
192
  @declared_options[option_symbol][:accessor]=AttrAccessor.new(object,attr_symb)
230
- set_option(option_symbol,default_value,"default obj attr") if !default_value.nil?
193
+ set_option(option_symbol,default_value,'default obj attr') if !default_value.nil?
231
194
  end
232
195
 
233
196
  # set an option value by name, either store value or call handler
234
- def set_option(option_symbol,value,where="default")
235
- if ! @declared_options.has_key?(option_symbol)
197
+ def set_option(option_symbol,value,where='default')
198
+ if !@declared_options.has_key?(option_symbol)
236
199
  Log.log.debug("set unknown option: #{option_symbol}")
237
- raise "ERROR: cannot set undeclared option"
200
+ raise 'ERROR: cannot set undeclared option'
238
201
  #declare_option(option_symbol)
239
202
  end
240
203
  value=ExtendedValue.instance.evaluate(value)
241
- Log.log.debug("set_option(#{where}) #{option_symbol}=#{value}")
242
- if @declared_options[option_symbol][:values].eql?(BOOLEAN_VALUES)
243
- value=enum_to_bool(value)
244
- end
245
- Log.log.debug("set #{option_symbol}=#{value} (#{@declared_options[option_symbol][:type]}) : #{where}".blue)
204
+ value=Manager.enum_to_bool(value) if @declared_options[option_symbol][:values].eql?(BOOLEAN_VALUES)
205
+ Log.log.debug("set #{option_symbol}=#{value} (#{@declared_options[option_symbol][:type]}) : #{where}")
246
206
  case @declared_options[option_symbol][:type]
247
207
  when :accessor
248
208
  @declared_options[option_symbol][:accessor].value=value
249
209
  when :value
250
210
  @declared_options[option_symbol][:value]=value
251
211
  else # nil or other
252
- raise "error"
212
+ raise 'error'
253
213
  end
254
214
  end
255
215
 
@@ -265,28 +225,25 @@ module Aspera
265
225
  when :value
266
226
  result=@declared_options[option_symbol][:value]
267
227
  else
268
- raise "unknown type"
228
+ raise 'unknown type'
269
229
  end
270
230
  Log.log.debug("get #{option_symbol} (#{@declared_options[option_symbol][:type]}) : #{result}")
271
231
  end
272
232
  # do not fail for manual generation if option mandatory but not set
273
- result||='' unless @fail_on_missing_mandatory
274
- Log.log.debug("interactive=#{@ask_missing_mandatory}")
233
+ result='' if result.nil? && !@fail_on_missing_mandatory
234
+ #Log.log.debug("interactive=#{@ask_missing_mandatory}")
275
235
  if result.nil?
276
236
  if !@ask_missing_mandatory
277
- if is_type.eql?(:mandatory)
278
- raise CliBadArgument,"Missing mandatory option: #{option_symbol}"
279
- end
280
- else # ask_missing_mandatory
281
- if @ask_missing_optional or is_type.eql?(:mandatory)
282
- expected=:single
283
- #print "please enter: #{option_symbol.to_s}"
284
- if @declared_options.has_key?(option_symbol) and @declared_options[option_symbol].has_key?(:values)
285
- expected=@declared_options[option_symbol][:values]
286
- end
287
- result=get_interactive(:option,option_symbol.to_s,expected)
288
- set_option(option_symbol,result,"interactive")
237
+ raise CliBadArgument,"Missing mandatory option: #{option_symbol}" if is_type.eql?(:mandatory)
238
+ elsif @ask_missing_optional || is_type.eql?(:mandatory)
239
+ # ask_missing_mandatory
240
+ expected=:single
241
+ #print "please enter: #{option_symbol.to_s}"
242
+ if @declared_options.has_key?(option_symbol) && @declared_options[option_symbol].has_key?(:values)
243
+ expected=@declared_options[option_symbol][:values]
289
244
  end
245
+ result=get_interactive(:option,option_symbol.to_s,expected)
246
+ set_option(option_symbol,result,'interactive')
290
247
  end
291
248
  end
292
249
  return result
@@ -300,17 +257,6 @@ module Aspera
300
257
  preset_hash.each{|k,v|@unprocessed_defaults.send(op,[k.to_sym,v])}
301
258
  end
302
259
 
303
- # generate command line option from option symbol
304
- def symbol_to_option(symbol,opt_val)
305
- result='--'+symbol.to_s.gsub(OPTION_SEP_NAME,OPTION_SEP_LINE)
306
- result=result+'='+opt_val unless opt_val.nil?
307
- return result
308
- end
309
-
310
- def highlight_current(value)
311
- STDOUT.isatty ? value.to_s.red.bold : "[#{value}]"
312
- end
313
-
314
260
  # define an option with restricted values
315
261
  def add_opt_list(option_symbol,values,help,*on_args)
316
262
  declare_option(option_symbol,:value)
@@ -321,12 +267,12 @@ module Aspera
321
267
  value=get_option(option_symbol)
322
268
  help_values=values.map{|i|i.eql?(value)?highlight_current(i):i}.join(', ')
323
269
  if values.eql?(BOOLEAN_VALUES)
324
- help_values=BOOLEAN_SIMPLE.map{|i|((i.eql?(:yes) and value) or (i.eql?(:no) and not value))?highlight_current(i):i}.join(', ')
270
+ help_values=BOOLEAN_SIMPLE.map{|i|(i.eql?(:yes) && value) || (i.eql?(:no) && !value) ? highlight_current(i) : i}.join(', ')
325
271
  end
326
272
  on_args.push(values)
327
273
  on_args.push("#{help}: #{help_values}")
328
274
  Log.log.debug("on_args=#{on_args}")
329
- @parser.on(*on_args){|v|set_option(option_symbol,self.class.get_from_list(v.to_s,help,values),"cmdline")}
275
+ @parser.on(*on_args){|v|set_option(option_symbol,self.class.get_from_list(v.to_s,help,values),'cmdline')}
330
276
  end
331
277
 
332
278
  def add_opt_boolean(option_symbol,help,*on_args)
@@ -337,22 +283,22 @@ module Aspera
337
283
  def add_opt_simple(option_symbol,*on_args)
338
284
  declare_option(option_symbol,:value)
339
285
  Log.log.debug("add_opt_simple #{option_symbol}")
340
- on_args.unshift(symbol_to_option(option_symbol,"VALUE"))
286
+ on_args.unshift(symbol_to_option(option_symbol,'VALUE'))
341
287
  Log.log.debug("on_args=#{on_args}")
342
- @parser.on(*on_args) { |v| set_option(option_symbol,v,"cmdline") }
288
+ @parser.on(*on_args) { |v| set_option(option_symbol,v,'cmdline') }
343
289
  end
344
290
 
345
291
  # define an option with date format
346
292
  def add_opt_date(option_symbol,*on_args)
347
293
  declare_option(option_symbol,:value)
348
294
  Log.log.debug("add_opt_date #{option_symbol}")
349
- on_args.unshift(symbol_to_option(option_symbol,"DATE"))
295
+ on_args.unshift(symbol_to_option(option_symbol,'DATE'))
350
296
  Log.log.debug("on_args=#{on_args}")
351
297
  @parser.on(*on_args) do |v|
352
298
  case v
353
- when 'now'; set_option(option_symbol,Manager.time_to_string(Time.now),"cmdline")
354
- when /^-([0-9]+)h/; set_option(option_symbol,Manager.time_to_string(Time.now-$1.to_i*3600),"cmdline")
355
- else set_option(option_symbol,v,"cmdline")
299
+ when 'now' then set_option(option_symbol,Manager.time_to_string(Time.now),'cmdline')
300
+ when /^-([0-9]+)h/ then set_option(option_symbol,Manager.time_to_string(Time.now-(3600*Regexp.last_match(1).to_i)),'cmdline')
301
+ else set_option(option_symbol,v,'cmdline')
356
302
  end
357
303
  end
358
304
  end
@@ -379,15 +325,15 @@ module Aspera
379
325
  end
380
326
 
381
327
  # get all original options on command line used to generate a config in config file
382
- def get_options_table(remove_from_remaining=true)
328
+ def get_options_table(remove_from_remaining: true)
383
329
  result={}
384
330
  @initial_cli_options.each do |optionval|
385
331
  case optionval
386
332
  when /^--([^=]+)$/
387
333
  # ignore
388
334
  when /^--([^=]+)=(.*)$/
389
- name=$1
390
- value=$2
335
+ name=Regexp.last_match(1)
336
+ value=Regexp.last_match(2)
391
337
  name.gsub!(OPTION_SEP_LINE,OPTION_SEP_NAME)
392
338
  value=ExtendedValue.instance.evaluate(value)
393
339
  Log.log.debug("option #{name}=#{value}")
@@ -401,46 +347,28 @@ module Aspera
401
347
  end
402
348
 
403
349
  # return options as taken from config file and command line just before command execution
404
- def declared_options(all=true)
405
- return @declared_options.keys.inject({}) do |h,option_symb|
350
+ def declared_options(only_defined: false)
351
+ result={}
352
+ @declared_options.keys.each do |option_symb|
406
353
  v=get_option(option_symb)
407
- h[option_symb.to_s]=v if all or !v.nil?
408
- h
354
+ result[option_symb.to_s]=v unless only_defined && v.nil?
409
355
  end
410
- end
411
-
412
- def apply_options_preset(preset,where,force=false)
413
- unprocessed=[]
414
- preset.each do |pair|
415
- k,v=*pair
416
- if @declared_options.has_key?(k)
417
- # constrained parameters as string are revert to symbol
418
- if @declared_options[k].has_key?(:values) and v.is_a?(String)
419
- v=self.class.get_from_list(v,k.to_s+" in #{where}",@declared_options[k][:values])
420
- end
421
- set_option(k,v,where)
422
- else
423
- unprocessed.push(pair)
424
- end
425
- end
426
- # keep only unprocessed values for next parse
427
- preset.clear
428
- preset.push(*unprocessed)
356
+ return result
429
357
  end
430
358
 
431
359
  # removes already known options from the list
432
360
  def parse_options!
433
- Log.log.debug("parse_options!".red)
361
+ Log.log.debug('parse_options!'.red)
434
362
  # first conf file, then env var
435
- apply_options_preset(@unprocessed_defaults,"file")
436
- apply_options_preset(@unprocessed_env,"env")
363
+ apply_options_preset(@unprocessed_defaults,'file')
364
+ apply_options_preset(@unprocessed_env,'env')
437
365
  # command line override
438
366
  unknown_options=[]
439
367
  begin
440
368
  # remove known options one by one, exception if unknown
441
- Log.log.debug("before parse".red)
369
+ Log.log.debug('before parse'.red)
442
370
  @parser.parse!(@unprocessed_cmd_line_options)
443
- Log.log.debug("After parse".red)
371
+ Log.log.debug('After parse'.red)
444
372
  rescue OptionParser::InvalidOption => e
445
373
  Log.log.debug("InvalidOption #{e}".red)
446
374
  # save for later processing
@@ -451,6 +379,70 @@ module Aspera
451
379
  # set unprocessed options for next time
452
380
  @unprocessed_cmd_line_options=unknown_options
453
381
  end
382
+
383
+ private
384
+
385
+ def prompt_user_input(prompt,sensitive)
386
+ return $stdin.getpass("#{prompt}> ") if sensitive
387
+ print "#{prompt}> "
388
+ return $stdin.gets.chomp
389
+ end
390
+
391
+ def get_interactive(type,descr,expected=:single)
392
+ if !@ask_missing_mandatory
393
+ raise CliBadArgument,self.class.bad_arg_message_multi("missing: #{descr}",expected) if expected.is_a?(Array)
394
+ raise CliBadArgument,"missing argument (#{expected}): #{descr}"
395
+ end
396
+ result=nil
397
+ sensitive = type.eql?(:option) && @declared_options[descr.to_sym][:sensitive]
398
+ default_prompt="#{type}: #{descr}"
399
+ # ask interactively
400
+ case expected
401
+ when :multiple
402
+ result=[]
403
+ puts(' (one per line, end with empty line)')
404
+ loop do
405
+ entry=prompt_user_input(default_prompt,sensitive)
406
+ break if entry.empty?
407
+ result.push(ExtendedValue.instance.evaluate(entry))
408
+ end
409
+ when :single
410
+ result=ExtendedValue.instance.evaluate(prompt_user_input(default_prompt,sensitive))
411
+ else # one fixed
412
+ result=self.class.get_from_list(prompt_user_input("#{expected.join(' ')}\n#{default_prompt}",sensitive),descr,expected)
413
+ end
414
+ return result
415
+ end
416
+
417
+ # generate command line option from option symbol
418
+ def symbol_to_option(symbol,opt_val)
419
+ result='--'+symbol.to_s.gsub(OPTION_SEP_NAME,OPTION_SEP_LINE)
420
+ result=result+'='+opt_val unless opt_val.nil?
421
+ return result
422
+ end
423
+
424
+ def highlight_current(value)
425
+ $stdout.isatty ? value.to_s.red.bold : "[#{value}]"
426
+ end
427
+
428
+ def apply_options_preset(preset,where)
429
+ unprocessed=[]
430
+ preset.each do |pair|
431
+ k,v=*pair
432
+ if @declared_options.has_key?(k)
433
+ # constrained parameters as string are revert to symbol
434
+ if @declared_options[k].has_key?(:values) && v.is_a?(String)
435
+ v=self.class.get_from_list(v,k.to_s+" in #{where}",@declared_options[k][:values])
436
+ end
437
+ set_option(k,v,where)
438
+ else
439
+ unprocessed.push(pair)
440
+ end
441
+ end
442
+ # keep only unprocessed values for next parse
443
+ preset.clear
444
+ preset.push(*unprocessed)
445
+ end
454
446
  end
455
447
  end
456
448
  end
@@ -1,51 +1,57 @@
1
+ # frozen_string_literal: true
1
2
  module Aspera
2
3
  module Cli
3
4
  # base class for plugins modules
4
5
  class Plugin
5
6
  # operation without id
6
- GLOBAL_OPS=[:create,:list]
7
+ GLOBAL_OPS=[:create,:list].freeze
7
8
  # operation on specific instance
8
- INSTANCE_OPS=[:modify,:delete,:show]
9
- ALL_OPS=[GLOBAL_OPS,INSTANCE_OPS].flatten
9
+ INSTANCE_OPS=[:modify,:delete,:show].freeze
10
+ ALL_OPS=[GLOBAL_OPS,INSTANCE_OPS].flatten.freeze
10
11
  # max number of items for list command
11
12
  MAX_ITEMS='max'
12
13
  # max number of pages for list command
13
14
  MAX_PAGES='pmax'
14
15
 
15
- @@done=false
16
+ # global for inherited classes
17
+ @@options_created=false # rubocop:disable Style/ClassVars
16
18
 
17
19
  def initialize(env)
18
20
  @agents=env
19
21
  raise StandardError,"execute_action shall be redefined by subclass #{self.class}" unless respond_to?(:execute_action)
20
- raise StandardError,"ACTIONS shall be redefined by subclass" unless self.class.constants.include?(:ACTIONS)
22
+ raise StandardError,'ACTIONS shall be redefined by subclass' unless self.class.constants.include?(:ACTIONS)
21
23
  unless env[:skip_option_header]
22
- self.options.parser.separator ""
23
- self.options.parser.separator "COMMAND: #{self.class.name.split('::').last.downcase}"
24
- self.options.parser.separator "SUBCOMMANDS: #{self.class.const_get(:ACTIONS).map{ |p| p.to_s}.join(' ')}"
25
- self.options.parser.separator "OPTIONS:"
26
- end
27
- unless @@done
28
- self.options.add_opt_simple(:value,"extended value for create, update, list filter")
29
- self.options.add_opt_simple(:property,"name of property to set")
30
- self.options.add_opt_simple(:id,"resource identifier (#{INSTANCE_OPS.join(",")})")
31
- self.options.parse_options!
32
- @@done=true
24
+ options.parser.separator ''
25
+ options.parser.separator "COMMAND: #{self.class.name.split('::').last.downcase}"
26
+ options.parser.separator "SUBCOMMANDS: #{self.class.const_get(:ACTIONS).map(&:to_s).join(' ')}"
27
+ options.parser.separator 'OPTIONS:'
33
28
  end
29
+ return if @@options_created
30
+ options.add_opt_simple(:value,'extended value for create, update, list filter')
31
+ options.add_opt_simple(:property,'name of property to set')
32
+ options.add_opt_simple(:id,"resource identifier (#{INSTANCE_OPS.join(',')})")
33
+ options.parse_options!
34
+ @@options_created=true # rubocop:disable Style/ClassVars
34
35
  end
35
36
 
36
37
  # must be called AFTER the instance action
37
- def instance_identifier()
38
- res_id=self.options.get_option(:id)
39
- res_id=self.options.get_next_argument('identifier') if res_id.nil?
38
+ def instance_identifier
39
+ res_id=options.get_option(:id)
40
+ res_id=options.get_next_argument('identifier') if res_id.nil?
40
41
  return res_id
41
42
  end
42
43
 
43
- def entity_command(command,rest_api,res_class_path,display_fields,id_symb,id_default=nil,use_subkey=false)
44
- raise "not id" unless :id.eql?(id_symb)
44
+ # @param command [Symbol] command to execute: create show list modify delete
45
+ # @param rest_api [Rest] api to use
46
+ # @param res_class_path [String] sub path in URL to resource relative to base url
47
+ # @param display_fields [Array] fields to display by default
48
+ # @param id_default [String] default identifier to use for existing entity commands (show, modify)
49
+ # @param use_subkey [bool] true if the result is in a subkey of the json
50
+ def entity_command(command,rest_api,res_class_path,display_fields: nil,id_default: nil,use_subkey: false)
45
51
  if INSTANCE_OPS.include?(command)
46
52
  begin
47
53
  one_res_id=instance_identifier()
48
- rescue => e
54
+ rescue StandardError => e
49
55
  raise e if id_default.nil?
50
56
  one_res_id=id_default
51
57
  end
@@ -53,17 +59,17 @@ module Aspera
53
59
  end
54
60
  # parameters mandatory for create/modify
55
61
  if [:create,:modify].include?(command)
56
- parameters=self.options.get_option(:value,:mandatory)
62
+ parameters=options.get_option(:value,:mandatory)
57
63
  end
58
64
  # parameters optional for list
59
65
  if [:list].include?(command)
60
- parameters=self.options.get_option(:value,:optional)
66
+ parameters=options.get_option(:value,:optional)
61
67
  end
62
68
  case command
63
69
  when :create
64
- return {:type => :single_object, :data=>rest_api.create(res_class_path,parameters)[:data], :fields=>display_fields}
70
+ return {type: :single_object, data: rest_api.create(res_class_path,parameters)[:data], fields: display_fields}
65
71
  when :show
66
- return {:type => :single_object, :data=>rest_api.read(one_res_path)[:data], :fields=>display_fields}
72
+ return {type: :single_object, data: rest_api.read(one_res_path)[:data], fields: display_fields}
67
73
  when :list
68
74
  resp=rest_api.read(res_class_path,parameters)
69
75
  data=resp[:data]
@@ -72,26 +78,25 @@ module Aspera
72
78
  data=data[res_class_path]
73
79
  end
74
80
  data=data[res_class_path] if use_subkey
75
- return {:type => :object_list, :data=>data, :fields=>display_fields}
81
+ return {type: :object_list, data: data, fields: display_fields}
76
82
  when :modify
77
- property=self.options.get_option(:property,:optional)
83
+ property=options.get_option(:property,:optional)
78
84
  parameters={property => parameters} unless property.nil?
79
85
  rest_api.update(one_res_path,parameters)
80
86
  return Main.result_status('modified')
81
87
  when :delete
82
88
  rest_api.delete(one_res_path)
83
- return Main.result_status("deleted")
89
+ return Main.result_status('deleted')
84
90
  else
85
91
  raise "unknown action: #{command}"
86
92
  end
87
- raise "internal error should not reach here"
88
93
  end
89
94
 
90
95
  # implement generic rest operations on given resource path
91
- def entity_action(rest_api,res_class_path,display_fields,id_symb,id_default=nil,use_subkey=false)
96
+ def entity_action(rest_api,res_class_path,**opts)
92
97
  #res_name=res_class_path.gsub(%r{^.*/},'').gsub(%r{s$},'').gsub('_',' ')
93
- command=self.options.get_next_command(ALL_OPS)
94
- return entity_command(command,rest_api,res_class_path,display_fields,id_symb,id_default,use_subkey)
98
+ command=options.get_next_command(ALL_OPS)
99
+ return entity_command(command,rest_api,res_class_path,**opts)
95
100
  end
96
101
 
97
102
  # shortcuts for plugin environment
@@ -104,7 +109,6 @@ module Aspera
104
109
  def format; return @agents[:formater];end
105
110
 
106
111
  def persistency; return @agents[:persistency];end
107
-
108
112
  end # Plugin
109
113
  end # Cli
110
114
  end # Aspera
@@ -1,3 +1,4 @@
1
+ # frozen_string_literal: true
1
2
  require 'aspera/rest'
2
3
  require 'aspera/aoc'
3
4
 
@@ -5,17 +6,16 @@ module Aspera
5
6
  module Cli
6
7
  module Plugins
7
8
  class Alee < BasicAuthPlugin
8
-
9
- ACTIONS=[ :entitlement ]
9
+ ACTIONS=[:entitlement]
10
10
 
11
11
  def execute_action
12
- command=self.options.get_next_command(ACTIONS)
12
+ command=options.get_next_command(ACTIONS)
13
13
  case command
14
14
  when :entitlement
15
- entitlement_id = self.options.get_option(:username,:mandatory)
16
- customer_id = self.options.get_option(:password,:mandatory)
15
+ entitlement_id = options.get_option(:username,:mandatory)
16
+ customer_id = options.get_option(:password,:mandatory)
17
17
  api_metering=AoC.metering_api(entitlement_id,customer_id)
18
- return {:type=>:single_object, :data=>api_metering.read('entitlement')[:data]}
18
+ return {type: :single_object, data: api_metering.read('entitlement')[:data]}
19
19
  end
20
20
  end
21
21
  end # Aspera