aspera-cli 4.2.1 → 4.5.0

Sign up to get free protection for your applications and to get access to all the features.
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