aspera-cli 4.2.1 → 4.5.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 (59) hide show
  1. checksums.yaml +4 -4
  2. data/README.md +1580 -946
  3. data/bin/ascli +1 -1
  4. data/bin/asession +3 -5
  5. data/docs/Makefile +8 -11
  6. data/docs/README.erb.md +1521 -829
  7. data/docs/doc_tools.rb +58 -0
  8. data/docs/test_env.conf +3 -1
  9. data/examples/faspex4.rb +28 -19
  10. data/examples/transfer.rb +2 -2
  11. data/lib/aspera/aoc.rb +157 -134
  12. data/lib/aspera/cli/listener/progress_multi.rb +5 -5
  13. data/lib/aspera/cli/main.rb +106 -48
  14. data/lib/aspera/cli/manager.rb +19 -20
  15. data/lib/aspera/cli/plugin.rb +22 -7
  16. data/lib/aspera/cli/plugins/aoc.rb +260 -208
  17. data/lib/aspera/cli/plugins/ats.rb +11 -10
  18. data/lib/aspera/cli/plugins/bss.rb +2 -2
  19. data/lib/aspera/cli/plugins/config.rb +360 -189
  20. data/lib/aspera/cli/plugins/faspex.rb +119 -56
  21. data/lib/aspera/cli/plugins/faspex5.rb +32 -17
  22. data/lib/aspera/cli/plugins/node.rb +72 -31
  23. data/lib/aspera/cli/plugins/orchestrator.rb +5 -3
  24. data/lib/aspera/cli/plugins/preview.rb +94 -68
  25. data/lib/aspera/cli/plugins/server.rb +16 -5
  26. data/lib/aspera/cli/plugins/shares.rb +17 -0
  27. data/lib/aspera/cli/transfer_agent.rb +64 -82
  28. data/lib/aspera/cli/version.rb +1 -1
  29. data/lib/aspera/command_line_builder.rb +48 -31
  30. data/lib/aspera/cos_node.rb +4 -3
  31. data/lib/aspera/environment.rb +4 -4
  32. data/lib/aspera/fasp/{manager.rb → agent_base.rb} +7 -6
  33. data/lib/aspera/fasp/{connect.rb → agent_connect.rb} +46 -39
  34. data/lib/aspera/fasp/{local.rb → agent_direct.rb} +42 -38
  35. data/lib/aspera/fasp/{http_gw.rb → agent_httpgw.rb} +50 -29
  36. data/lib/aspera/fasp/{node.rb → agent_node.rb} +43 -4
  37. data/lib/aspera/fasp/agent_trsdk.rb +106 -0
  38. data/lib/aspera/fasp/default.rb +17 -0
  39. data/lib/aspera/fasp/installation.rb +64 -48
  40. data/lib/aspera/fasp/parameters.rb +78 -91
  41. data/lib/aspera/fasp/parameters.yaml +531 -0
  42. data/lib/aspera/fasp/uri.rb +1 -1
  43. data/lib/aspera/faspex_gw.rb +12 -11
  44. data/lib/aspera/id_generator.rb +22 -0
  45. data/lib/aspera/keychain/encrypted_hash.rb +120 -0
  46. data/lib/aspera/keychain/macos_security.rb +94 -0
  47. data/lib/aspera/log.rb +45 -32
  48. data/lib/aspera/node.rb +9 -4
  49. data/lib/aspera/oauth.rb +116 -100
  50. data/lib/aspera/persistency_action_once.rb +11 -7
  51. data/lib/aspera/persistency_folder.rb +6 -26
  52. data/lib/aspera/rest.rb +66 -50
  53. data/lib/aspera/sync.rb +40 -35
  54. data/lib/aspera/timer_limiter.rb +22 -0
  55. metadata +86 -29
  56. data/docs/transfer_spec.html +0 -99
  57. data/lib/aspera/api_detector.rb +0 -60
  58. data/lib/aspera/fasp/aoc.rb +0 -24
  59. data/lib/aspera/secrets.rb +0 -20
@@ -4,82 +4,96 @@ require 'aspera/cli/plugins/config'
4
4
  require 'aspera/cli/extended_value'
5
5
  require 'aspera/cli/transfer_agent'
6
6
  require 'aspera/cli/version'
7
+ require 'aspera/fasp/error'
7
8
  require 'aspera/open_application'
8
9
  require 'aspera/temp_file_manager'
9
10
  require 'aspera/persistency_folder'
10
11
  require 'aspera/log'
11
12
  require 'aspera/rest'
12
13
  require 'aspera/nagios'
13
- require 'aspera/secrets'
14
14
 
15
15
  module Aspera
16
16
  module Cli
17
17
  # The main CLI class
18
18
  class Main
19
19
 
20
- attr_reader :plugin_env
21
20
  private
22
- # name of application, also foldername where config is stored
21
+ # name of application, also used as foldername where config is stored
23
22
  PROGRAM_NAME = 'ascli'
23
+ # name of the containing gem, same as in <gem name>.gemspec
24
24
  GEM_NAME = 'aspera-cli'
25
- VERBOSE_LEVELS=[:normal,:minimal,:quiet]
26
-
27
- private_constant :PROGRAM_NAME,:GEM_NAME,:VERBOSE_LEVELS
25
+ HELP_URL = "http://www.rubydoc.info/gems/#{GEM_NAME}"
26
+ GEM_URL = "https://rubygems.org/gems/#{GEM_NAME}"
27
+ SRC_URL = 'https://github.com/IBM/aspera-cli'
28
+ # store transfer result using this key and use result_transfer_multiple
29
+ STATUS_FIELD = 'status'
28
30
 
31
+ private_constant :PROGRAM_NAME,:GEM_NAME,:HELP_URL,:GEM_URL
29
32
  # =============================================================
30
33
  # Parameter handlers
31
34
  #
32
-
33
- def option_insecure; Rest.insecure ; end
34
-
35
- def option_insecure=(value); Rest.insecure = value; end
36
-
35
+ attr_accessor :option_insecure, :option_http_options
37
36
  def option_ui; OpenApplication.instance.url_method; end
38
37
 
39
38
  def option_ui=(value); OpenApplication.instance.url_method=value; end
40
39
 
40
+ # called everytime a new REST HTTP session is opened
41
+ # @param http [Net::HTTP] the newly created http session object
42
+ def set_http_parameters(http)
43
+ http.verify_mode = OpenSSL::SSL::VERIFY_NONE if @option_insecure
44
+ http.set_debug_output($stdout) if @option_rest_debug
45
+ raise "http_options expects Hash" unless @option_http_options.is_a?(Hash)
46
+ @option_http_options.each do |k,v|
47
+ method="#{k}=".to_sym
48
+ # check if accessor is a method of Net::HTTP
49
+ # continue_timeout= read_timeout= write_timeout=
50
+ if http.respond_to?(method)
51
+ http.send(method,v)
52
+ else
53
+ Log.log.error("no such attribute: #{k}")
54
+ end
55
+ end
56
+ end
57
+
41
58
  # minimum initialization
42
59
  def initialize(argv)
43
- # first thing : manage debug level (allows debugging or option parser)
60
+ # first thing : manage debug level (allows debugging of option parser)
44
61
  early_debug_setup(argv)
62
+ # compare $0 with expected name
45
63
  current_prog_name=File.basename($PROGRAM_NAME)
46
64
  unless current_prog_name.eql?(PROGRAM_NAME)
47
65
  @plugin_env[:formater].display_message(:error,"#{"WARNING".bg_red.blink.gray} Please use '#{PROGRAM_NAME}' instead of '#{current_prog_name}', '#{current_prog_name}' will be removed in a future version")
48
66
  end
49
- # overriding parameters on transfer spec
50
67
  @option_help=false
51
68
  @bash_completion=false
52
69
  @option_show_config=false
70
+ @option_insecure=false
71
+ @option_rest_debug=false
72
+ @option_http_options={}
73
+ # environment provided to plugin for various capabilities
53
74
  @plugin_env={}
54
- @help_url='http://www.rubydoc.info/gems/'+GEM_NAME
55
- @gem_url='https://rubygems.org/gems/'+GEM_NAME
56
- # give command line arguments to option manager (no parsing)
57
- app_main_folder=ENV[conf_dir_env_var]
58
- # if env var undefined or empty
59
- if app_main_folder.nil? or app_main_folder.empty?
60
- user_home_folder=Dir.home
61
- raise CliError,"Home folder does not exist: #{user_home_folder}. Check your user environment or use #{conf_dir_env_var}." unless Dir.exist?(user_home_folder)
62
- app_main_folder=File.join(user_home_folder,Plugins::Config::ASPERA_HOME_FOLDER_NAME,PROGRAM_NAME)
63
- end
64
- @plugin_env[:options]=@opt_mgr=Manager.new(PROGRAM_NAME,argv,app_banner())
75
+ # give command line arguments to option manager
76
+ @plugin_env[:options]=@opt_mgr=Manager.new(PROGRAM_NAME,argv)
77
+ # formatter adds options
65
78
  @plugin_env[:formater]=Formater.new(@plugin_env[:options])
66
79
  Rest.user_agent=PROGRAM_NAME
67
- # must override help methods before parser called (in other constructors)
80
+ Rest.session_cb=lambda {|http| set_http_parameters(http)}
81
+ # declare and parse global options
68
82
  init_global_options()
69
- # secret manager
70
- @plugin_env[:secret]=Aspera::Secrets.new
71
- # the Config plugin adds the @preset parser
72
- @plugin_env[:config]=Plugins::Config.new(@plugin_env,PROGRAM_NAME,@help_url,Aspera::Cli::VERSION,app_main_folder)
83
+ # the Config plugin adds the @preset parser, so declare before TransferAgent which may use it
84
+ @plugin_env[:config]=Plugins::Config.new(@plugin_env,PROGRAM_NAME,HELP_URL,Aspera::Cli::VERSION,app_main_folder)
73
85
  # the TransferAgent plugin may use the @preset parser
74
- @plugin_env[:transfer]=TransferAgent.new(@plugin_env)
75
- Log.log.debug('created plugin env'.red)
76
- # set application folder for modules
86
+ @plugin_env[:transfer]=TransferAgent.new(@plugin_env[:options],@plugin_env[:config])
87
+ # data persistency
77
88
  @plugin_env[:persistency]=PersistencyFolder.new(File.join(@plugin_env[:config].main_folder,'persist_store'))
89
+ Log.log.debug('plugin env created'.red)
78
90
  Oauth.persist_mgr=@plugin_env[:persistency]
79
91
  Fasp::Parameters.file_list_folder=File.join(@plugin_env[:config].main_folder,'filelists')
80
92
  Aspera::RestErrorAnalyzer.instance.log_file=File.join(@plugin_env[:config].main_folder,'rest_exceptions.log')
81
93
  # register aspera REST call error handlers
82
94
  Aspera::RestErrorsAspera.registerHandlers
95
+ # set banner when all environment is created so that additional extended value modifiers are known, e.g. @preset
96
+ @opt_mgr.parser.banner=app_banner
83
97
  end
84
98
 
85
99
  def app_banner
@@ -88,18 +102,19 @@ module Aspera
88
102
  banner << "\t#{PROGRAM_NAME} COMMANDS [OPTIONS] [ARGS]\n"
89
103
  banner << "\nDESCRIPTION\n"
90
104
  banner << "\tUse Aspera application to perform operations on command line.\n"
91
- banner << "\tDocumentation and examples: #{@gem_url}\n"
105
+ banner << "\tDocumentation and examples: #{GEM_URL}\n"
92
106
  banner << "\texecute: #{PROGRAM_NAME} conf doc\n"
93
- banner << "\tor visit: #{@help_url}\n"
107
+ banner << "\tor visit: #{HELP_URL}\n"
108
+ banner << "\tsource repo: #{SRC_URL}\n"
94
109
  banner << "\nENVIRONMENT VARIABLES\n"
95
110
  banner << "\t#{conf_dir_env_var} config folder, default: $HOME/#{Plugins::Config::ASPERA_HOME_FOLDER_NAME}/#{PROGRAM_NAME}\n"
96
- banner << "\t#any option can be set as an environment variable, refer to the manual\n"
111
+ banner << "\tany option can be set as an environment variable, refer to the manual\n"
97
112
  banner << "\nCOMMANDS\n"
98
113
  banner << "\tTo list first level commands, execute: #{PROGRAM_NAME}\n"
99
114
  banner << "\tNote that commands can be written shortened (provided it is unique).\n"
100
115
  banner << "\nOPTIONS\n"
101
116
  banner << "\tOptions begin with a '-' (minus), and value is provided on command line.\n"
102
- banner << "\tSpecial values are supported beginning with special prefix, like: #{ExtendedValue.instance.modifiers.map{|m|"@#{m}:"}.join(' ')}.\n"
117
+ banner << "\tSpecial values are supported beginning with special prefix @pfx:, where pfx is one of:\n\t#{ExtendedValue.instance.modifiers.map{|m|m.to_s}.join(', ')}\n"
103
118
  banner << "\tDates format is 'DD-MM-YY HH:MM:SS', or 'now' or '-<num>h'\n\n"
104
119
  banner << "ARGS\n"
105
120
  banner << "\tSome commands require mandatory arguments, e.g. a path.\n"
@@ -111,7 +126,7 @@ module Aspera
111
126
  @opt_mgr.add_opt_switch(:help,"-h","Show this message.") { @option_help=true }
112
127
  @opt_mgr.add_opt_switch(:bash_comp,"generate bash completion for command") { @bash_completion=true }
113
128
  @opt_mgr.add_opt_switch(:show_config, "Display parameters used for the provided action.") { @option_show_config=true }
114
- @opt_mgr.add_opt_switch(:rest_debug,"-r","more debug for HTTP calls") { Rest.debug=true }
129
+ @opt_mgr.add_opt_switch(:rest_debug,"-r","more debug for HTTP calls") { @option_rest_debug=true }
115
130
  @opt_mgr.add_opt_switch(:version,'-v','display version') { @plugin_env[:formater].display_message(:data,Aspera::Cli::VERSION);Process.exit(0) }
116
131
  @opt_mgr.add_opt_switch(:warnings,'-w','check for language warnings') { $VERBOSE=true }
117
132
  # handler must be set before declaration
@@ -119,13 +134,17 @@ module Aspera
119
134
  @opt_mgr.set_obj_attr(:logger,Log.instance,:logger_type)
120
135
  @opt_mgr.set_obj_attr(:insecure,self,:option_insecure,:no)
121
136
  @opt_mgr.set_obj_attr(:ui,self,:option_ui)
137
+ @opt_mgr.set_obj_attr(:http_options,self,:option_http_options)
138
+ @opt_mgr.set_obj_attr(:log_passwords,Log.instance,:log_passwords)
122
139
  @opt_mgr.add_opt_list(:ui,OpenApplication.user_interfaces,'method to start browser')
123
140
  @opt_mgr.add_opt_list(:log_level,Log.levels,"Log level")
124
141
  @opt_mgr.add_opt_list(:logger,Log.logtypes,"log method")
125
142
  @opt_mgr.add_opt_simple(:lock_port,"prevent dual execution of a command, e.g. in cron")
126
143
  @opt_mgr.add_opt_simple(:query,"additional filter for API calls (extended value) (some commands)")
144
+ @opt_mgr.add_opt_simple(:http_options,"options for http socket (extended value)")
127
145
  @opt_mgr.add_opt_boolean(:insecure,"do not validate HTTPS certificate")
128
146
  @opt_mgr.add_opt_boolean(:once_only,"process only new items (some commands)")
147
+ @opt_mgr.add_opt_boolean(:log_passwords,"show passwords in logs")
129
148
  @opt_mgr.set_option(:ui,OpenApplication.default_gui_mode)
130
149
  @opt_mgr.set_option(:once_only,:false)
131
150
  # parse declared options
@@ -141,7 +160,7 @@ module Aspera
141
160
  require @plugin_env[:config].plugins[plugin_name_sym][:require_stanza]
142
161
  # load default params only if no param already loaded before plugin instanciation
143
162
  env[:config].add_plugin_default_preset(plugin_name_sym)
144
- command_plugin=Plugins::Config.plugin_new(plugin_name_sym,env)
163
+ command_plugin=Plugins::Config.plugin_class(plugin_name_sym).new(env)
145
164
  Log.log.debug("got #{command_plugin.class}")
146
165
  # TODO: check that ancestor is Plugin?
147
166
  return command_plugin
@@ -177,10 +196,11 @@ module Aspera
177
196
  # override main option parser with a brand new, to avoid having global options
178
197
  plugin_env=@plugin_env.clone
179
198
  plugin_env[:man_only]=true
180
- plugin_env[:options]=Manager.new(PROGRAM_NAME,[],'')
199
+ plugin_env[:options]=Manager.new(PROGRAM_NAME)
200
+ plugin_env[:options].parser.banner='' # remove default banner
181
201
  get_plugin_instance_with_options(plugin_name_sym,plugin_env)
182
202
  # display generated help for plugin options
183
- @plugin_env[:formater].display_message(:error,plugin_env[:options].parser.to_s)
203
+ @plugin_env[:formater].display_message(:error,plugin_env[:options].parser.help)
184
204
  end
185
205
  end
186
206
  Process.exit(0)
@@ -188,10 +208,24 @@ module Aspera
188
208
 
189
209
  protected
190
210
 
211
+ # env var name to override the app's main folder
212
+ # default main folder is $HOME/<vendor main app folder>/<program name>
191
213
  def conf_dir_env_var
192
214
  return "#{PROGRAM_NAME}_home".upcase
193
215
  end
194
216
 
217
+ def app_main_folder
218
+ # find out application main folder
219
+ app_folder=ENV[conf_dir_env_var]
220
+ # if env var undefined or empty
221
+ if app_folder.nil? or app_folder.empty?
222
+ user_home_folder=Dir.home
223
+ raise CliError,"Home folder does not exist: #{user_home_folder}. Check your user environment or use #{conf_dir_env_var}." unless Dir.exist?(user_home_folder)
224
+ app_folder=File.join(user_home_folder,Plugins::Config::ASPERA_HOME_FOLDER_NAME,PROGRAM_NAME)
225
+ end
226
+ return app_folder
227
+ end
228
+
195
229
  # early debug for parser
196
230
  # Note: does not accept shortcuts
197
231
  def early_debug_setup(argv)
@@ -219,19 +253,35 @@ module Aspera
219
253
  return Main.result_nothing
220
254
  end
221
255
 
256
+ # used when one command executes several transfer jobs (each job being possibly multi session)
257
+ # @param status_table [Array] [{STATUS_FIELD=>[status array],...},...]
258
+ # @return a status object suitable as command result
259
+ # each element has a key STATUS_FIELD which contains the result of possibly multiple sessions
260
+ def self.result_transfer_multiple(status_table)
261
+ global_status=:success
262
+ # transform status array into string and find if there was problem
263
+ status_table.each do |item|
264
+ worst=TransferAgent.session_status(item[STATUS_FIELD])
265
+ global_status=worst unless worst.eql?(:success)
266
+ item[STATUS_FIELD]=item[STATUS_FIELD].map{|i|i.to_s}.join(',')
267
+ end
268
+ raise global_status unless global_status.eql?(:success)
269
+ return {:type=>:object_list,:data=>status_table}
270
+ end
271
+
222
272
  # this is the main function called by initial script just after constructor
223
273
  def process_command_line
224
274
  Log.log.debug('process_command_line')
275
+ # catch exception information , if any
225
276
  exception_info=nil
277
+ # false if command shall not be executed ("once_only")
278
+ execute_command=true
226
279
  begin
227
280
  # find plugins, shall be after parse! ?
228
281
  @plugin_env[:config].add_plugins_from_lookup_folders
229
282
  # help requested without command ? (plugins must be known here)
230
283
  exit_with_usage(true) if @option_help and @opt_mgr.command_or_arg_empty?
231
284
  generate_bash_completion if @bash_completion
232
- # load global default options and process
233
- @plugin_env[:config].add_plugin_default_preset(Plugins::Config::CONF_GLOBAL_SYM)
234
- @opt_mgr.parse_options!
235
285
  @plugin_env[:config].periodic_check_newer_gem_version
236
286
  if @option_show_config and @opt_mgr.command_or_arg_empty?
237
287
  command_sym=Plugins::Config::CONF_PLUGIN_SYM
@@ -264,11 +314,12 @@ module Aspera
264
314
  Log.log.debug("Opening lock port #{lock_port.to_i}")
265
315
  @tcp_server=TCPServer.new('127.0.0.1',lock_port.to_i)
266
316
  rescue => e
267
- raise CliError,"Another instance is already running (#{e.message})."
317
+ execute_command=false
318
+ Log.log.warn("Another instance is already running (#{e.message}).")
268
319
  end
269
320
  end
270
- # execute and display
271
- @plugin_env[:formater].display_results(command_plugin.execute_action)
321
+ # execute and display (if not exclusive execution)
322
+ @plugin_env[:formater].display_results(command_plugin.execute_action) if execute_command
272
323
  # finish
273
324
  @plugin_env[:transfer].shutdown
274
325
  rescue CliBadArgument => e; exception_info=[e,'Argument',:usage]
@@ -286,10 +337,17 @@ module Aspera
286
337
  unless exception_info.nil?
287
338
  @plugin_env[:formater].display_message(:error,"ERROR:".bg_red.gray.blink+" "+exception_info[1]+": "+exception_info[0].message)
288
339
  @plugin_env[:formater].display_message(:error,"Use '-h' option to get help.") if exception_info[2].eql?(:usage)
340
+ if exception_info.first.is_a?(Fasp::Error) and exception_info.first.message.eql?('Remote host is not who we expected')
341
+ @plugin_env[:formater].display_message(:error,"For this specific error, refer to:\n#{SRC_URL}#error-remote-host-is-not-who-we-expected\nAdd this to arguments:\n--ts=@json:'{\"sshfp\":null}'")
342
+ end
289
343
  end
290
344
  # 2- processing of command not processed (due to exception or bad command line)
291
- @opt_mgr.final_errors.each do |msg|
292
- @plugin_env[:formater].display_message(:error,"ERROR:".bg_red.gray.blink+" Argument: "+msg)
345
+ if execute_command
346
+ @opt_mgr.final_errors.each do |msg|
347
+ @plugin_env[:formater].display_message(:error,"ERROR:".bg_red.gray.blink+" Argument: "+msg)
348
+ # add code as exception if there is not already an error
349
+ exception_info=[Exception.new(msg),'UnusedArg'] if exception_info.nil?
350
+ end
293
351
  end
294
352
  # 3- in case of error, fail the process status
295
353
  unless exception_info.nil?
@@ -79,7 +79,7 @@ module Aspera
79
79
  attr_accessor :ask_missing_optional
80
80
 
81
81
  #
82
- def initialize(program_name,argv,app_banner)
82
+ def initialize(program_name,argv=nil)
83
83
  # command line values not starting with '-'
84
84
  @unprocessed_cmd_line_arguments=[]
85
85
  # command line values starting with '-'
@@ -98,7 +98,6 @@ module Aspera
98
98
  # Note: was initially inherited but it is prefered to have specific methods
99
99
  @parser=OptionParser.new
100
100
  @parser.program_name=program_name
101
- @parser.banner=app_banner
102
101
  # options can also be provided by env vars : --param-name -> ASLMCLI_PARAM_NAME
103
102
  env_prefix=program_name.upcase+OPTION_SEP_NAME
104
103
  ENV.each do |k,v|
@@ -107,29 +106,29 @@ module Aspera
107
106
  end
108
107
  end
109
108
  Log.log.debug("env=#{@unprocessed_env}".red)
110
- # banner is empty when help is generated for every plugin
111
- unless app_banner.empty?
112
- @parser.separator("")
113
- @parser.separator("OPTIONS: global")
109
+ @unprocessed_cmd_line_options=[]
110
+ @unprocessed_cmd_line_arguments=[]
111
+ # argv is nil when help is generated for every plugin
112
+ unless argv.nil?
113
+ @parser.separator('')
114
+ @parser.separator('OPTIONS: global')
114
115
  self.set_obj_attr(:interactive,self,:ask_missing_mandatory)
115
116
  self.set_obj_attr(:ask_options,self,:ask_missing_optional)
116
- self.add_opt_boolean(:interactive,"use interactive input of missing params")
117
- self.add_opt_boolean(:ask_options,"ask even optional options")
117
+ self.add_opt_boolean(:interactive,'use interactive input of missing params')
118
+ self.add_opt_boolean(:ask_options,'ask even optional options')
118
119
  self.parse_options!
119
- end
120
- @unprocessed_cmd_line_options=[]
121
- @unprocessed_cmd_line_arguments=[]
122
- process_options=true
123
- while !argv.empty?
124
- value=argv.shift
125
- if process_options and value.start_with?('-')
126
- if value.eql?('--')
127
- process_options=false
120
+ process_options=true
121
+ while !argv.empty?
122
+ value=argv.shift
123
+ if process_options and value.start_with?('-')
124
+ if value.eql?('--')
125
+ process_options=false
126
+ else
127
+ @unprocessed_cmd_line_options.push(value)
128
+ end
128
129
  else
129
- @unprocessed_cmd_line_options.push(value)
130
+ @unprocessed_cmd_line_arguments.push(value)
130
131
  end
131
- else
132
- @unprocessed_cmd_line_arguments.push(value)
133
132
  end
134
133
  end
135
134
  @initial_cli_options=@unprocessed_cmd_line_options.dup
@@ -2,10 +2,15 @@ module Aspera
2
2
  module Cli
3
3
  # base class for plugins modules
4
4
  class Plugin
5
+ # operation without id
5
6
  GLOBAL_OPS=[:create,:list]
7
+ # operation on specific instance
6
8
  INSTANCE_OPS=[:modify,:delete,:show]
7
9
  ALL_OPS=[GLOBAL_OPS,INSTANCE_OPS].flatten
8
- #private_constant :GLOBAL_OPS,:INSTANCE_OPS,:ALL_OPS
10
+ # max number of items for list command
11
+ MAX_ITEMS='max'
12
+ # max number of pages for list command
13
+ MAX_PAGES='pmax'
9
14
 
10
15
  @@done=false
11
16
 
@@ -28,10 +33,18 @@ module Aspera
28
33
  end
29
34
  end
30
35
 
31
- def entity_command(command,rest_api,res_class_path,display_fields,id_symb,id_default=nil,subkey=false)
36
+ # 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?
40
+ return res_id
41
+ end
42
+
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)
32
45
  if INSTANCE_OPS.include?(command)
33
46
  begin
34
- one_res_id=self.options.get_option(id_symb,:mandatory)
47
+ one_res_id=instance_identifier()
35
48
  rescue => e
36
49
  raise e if id_default.nil?
37
50
  one_res_id=id_default
@@ -54,10 +67,11 @@ module Aspera
54
67
  when :list
55
68
  resp=rest_api.read(res_class_path,parameters)
56
69
  data=resp[:data]
70
+ # TODO: not generic : which application is this for ?
57
71
  if resp[:http]['Content-Type'].start_with?('application/vnd.api+json')
58
- data=resp[:data][res_class_path]
72
+ data=data[res_class_path]
59
73
  end
60
- data=data[res_class_path] if subkey
74
+ data=data[res_class_path] if use_subkey
61
75
  return {:type => :object_list, :data=>data, :fields=>display_fields}
62
76
  when :modify
63
77
  property=self.options.get_option(:property,:optional)
@@ -74,12 +88,13 @@ module Aspera
74
88
  end
75
89
 
76
90
  # implement generic rest operations on given resource path
77
- def entity_action(rest_api,res_class_path,display_fields,id_symb,id_default=nil,subkey=false)
91
+ def entity_action(rest_api,res_class_path,display_fields,id_symb,id_default=nil,use_subkey=false)
78
92
  #res_name=res_class_path.gsub(%r{^.*/},'').gsub(%r{s$},'').gsub('_',' ')
79
93
  command=self.options.get_next_command(ALL_OPS)
80
- return entity_command(command,rest_api,res_class_path,display_fields,id_symb,id_default,subkey)
94
+ return entity_command(command,rest_api,res_class_path,display_fields,id_symb,id_default,use_subkey)
81
95
  end
82
96
 
97
+ # shortcuts for plugin environment
83
98
  def options; return @agents[:options];end
84
99
 
85
100
  def transfer; return @agents[:transfer];end