aspera-cli 4.0.0.pre1
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/README.md +3592 -0
- data/bin/ascli +7 -0
- data/bin/asession +89 -0
- data/docs/Makefile +59 -0
- data/docs/README.erb.md +3012 -0
- data/docs/README.md +13 -0
- data/docs/diagrams.txt +49 -0
- data/docs/secrets.make +38 -0
- data/docs/test_env.conf +117 -0
- data/docs/transfer_spec.html +99 -0
- data/examples/aoc.rb +17 -0
- data/examples/proxy.pac +60 -0
- data/examples/transfer.rb +115 -0
- data/lib/aspera/api_detector.rb +60 -0
- data/lib/aspera/ascmd.rb +151 -0
- data/lib/aspera/ats_api.rb +43 -0
- data/lib/aspera/cli/basic_auth_plugin.rb +38 -0
- data/lib/aspera/cli/extended_value.rb +88 -0
- data/lib/aspera/cli/formater.rb +238 -0
- data/lib/aspera/cli/listener/line_dump.rb +17 -0
- data/lib/aspera/cli/listener/logger.rb +20 -0
- data/lib/aspera/cli/listener/progress.rb +52 -0
- data/lib/aspera/cli/listener/progress_multi.rb +91 -0
- data/lib/aspera/cli/main.rb +304 -0
- data/lib/aspera/cli/manager.rb +440 -0
- data/lib/aspera/cli/plugin.rb +90 -0
- data/lib/aspera/cli/plugins/alee.rb +24 -0
- data/lib/aspera/cli/plugins/ats.rb +231 -0
- data/lib/aspera/cli/plugins/bss.rb +71 -0
- data/lib/aspera/cli/plugins/config.rb +806 -0
- data/lib/aspera/cli/plugins/console.rb +62 -0
- data/lib/aspera/cli/plugins/cos.rb +106 -0
- data/lib/aspera/cli/plugins/faspex.rb +377 -0
- data/lib/aspera/cli/plugins/faspex5.rb +93 -0
- data/lib/aspera/cli/plugins/node.rb +438 -0
- data/lib/aspera/cli/plugins/oncloud.rb +937 -0
- data/lib/aspera/cli/plugins/orchestrator.rb +169 -0
- data/lib/aspera/cli/plugins/preview.rb +464 -0
- data/lib/aspera/cli/plugins/server.rb +216 -0
- data/lib/aspera/cli/plugins/shares.rb +63 -0
- data/lib/aspera/cli/plugins/shares2.rb +114 -0
- data/lib/aspera/cli/plugins/sync.rb +65 -0
- data/lib/aspera/cli/plugins/xnode.rb +115 -0
- data/lib/aspera/cli/transfer_agent.rb +251 -0
- data/lib/aspera/cli/version.rb +5 -0
- data/lib/aspera/colors.rb +39 -0
- data/lib/aspera/command_line_builder.rb +137 -0
- data/lib/aspera/fasp/aoc.rb +24 -0
- data/lib/aspera/fasp/connect.rb +99 -0
- data/lib/aspera/fasp/error.rb +21 -0
- data/lib/aspera/fasp/error_info.rb +60 -0
- data/lib/aspera/fasp/http_gw.rb +81 -0
- data/lib/aspera/fasp/installation.rb +240 -0
- data/lib/aspera/fasp/listener.rb +11 -0
- data/lib/aspera/fasp/local.rb +377 -0
- data/lib/aspera/fasp/manager.rb +69 -0
- data/lib/aspera/fasp/node.rb +88 -0
- data/lib/aspera/fasp/parameters.rb +235 -0
- data/lib/aspera/fasp/resume_policy.rb +76 -0
- data/lib/aspera/fasp/uri.rb +51 -0
- data/lib/aspera/faspex_gw.rb +196 -0
- data/lib/aspera/hash_ext.rb +28 -0
- data/lib/aspera/log.rb +80 -0
- data/lib/aspera/nagios.rb +71 -0
- data/lib/aspera/node.rb +14 -0
- data/lib/aspera/oauth.rb +319 -0
- data/lib/aspera/on_cloud.rb +421 -0
- data/lib/aspera/open_application.rb +72 -0
- data/lib/aspera/persistency_action_once.rb +42 -0
- data/lib/aspera/persistency_folder.rb +91 -0
- data/lib/aspera/preview/file_types.rb +300 -0
- data/lib/aspera/preview/generator.rb +258 -0
- data/lib/aspera/preview/image_error.png +0 -0
- data/lib/aspera/preview/options.rb +35 -0
- data/lib/aspera/preview/utils.rb +131 -0
- data/lib/aspera/preview/video_error.png +0 -0
- data/lib/aspera/proxy_auto_config.erb.js +287 -0
- data/lib/aspera/proxy_auto_config.rb +34 -0
- data/lib/aspera/rest.rb +296 -0
- data/lib/aspera/rest_call_error.rb +13 -0
- data/lib/aspera/rest_error_analyzer.rb +98 -0
- data/lib/aspera/rest_errors_aspera.rb +58 -0
- data/lib/aspera/ssh.rb +53 -0
- data/lib/aspera/sync.rb +82 -0
- data/lib/aspera/temp_file_manager.rb +37 -0
- data/lib/aspera/uri_reader.rb +25 -0
- metadata +288 -0
@@ -0,0 +1,440 @@
|
|
1
|
+
require 'aspera/colors'
|
2
|
+
require 'aspera/log'
|
3
|
+
require 'aspera/cli/extended_value'
|
4
|
+
require 'optparse'
|
5
|
+
|
6
|
+
module Aspera
|
7
|
+
module Cli
|
8
|
+
# raised by cli on error conditions
|
9
|
+
class CliError < StandardError; end
|
10
|
+
|
11
|
+
# raised when an unexpected argument is provided
|
12
|
+
class CliBadArgument < CliError; end
|
13
|
+
|
14
|
+
class CliNoSuchId < CliError
|
15
|
+
def initialize(res_type,res_id)
|
16
|
+
msg="No such #{res_type} identifier: #{res_id}"
|
17
|
+
super(msg)
|
18
|
+
end
|
19
|
+
end
|
20
|
+
|
21
|
+
# option is retrieved from another object using accessor
|
22
|
+
class AttrAccessor
|
23
|
+
#attr_accessor :object
|
24
|
+
#attr_accessor :attr_symb
|
25
|
+
def initialize(object,attr_symb)
|
26
|
+
@object=object
|
27
|
+
@attr_symb=attr_symb
|
28
|
+
end
|
29
|
+
|
30
|
+
def value
|
31
|
+
@object.send(@attr_symb.to_s)
|
32
|
+
end
|
33
|
+
|
34
|
+
def value=(val)
|
35
|
+
@object.send(@attr_symb.to_s+'=',val)
|
36
|
+
end
|
37
|
+
end
|
38
|
+
|
39
|
+
# parse command line options
|
40
|
+
# arguments options start with '-', others are commands
|
41
|
+
# resolves on extended value syntax
|
42
|
+
class Manager
|
43
|
+
def self.time_to_string(time)
|
44
|
+
time.strftime("%Y-%m-%d %H:%M:%S")
|
45
|
+
end
|
46
|
+
|
47
|
+
# boolean options are set to true/false from the following values
|
48
|
+
TRUE_VALUES=[:yes,true]
|
49
|
+
BOOLEAN_VALUES=TRUE_VALUES.clone.push(:no,false)
|
50
|
+
BOOLEAN_SIMPLE=[:yes,:no]
|
51
|
+
# option name separator on command line
|
52
|
+
OPTION_SEP_LINE='-'
|
53
|
+
# option name separator in code (symbol)
|
54
|
+
OPTION_SEP_NAME='_'
|
55
|
+
|
56
|
+
private_constant :TRUE_VALUES,:BOOLEAN_VALUES,:BOOLEAN_SIMPLE,:OPTION_SEP_LINE,:OPTION_SEP_NAME
|
57
|
+
|
58
|
+
def enum_to_bool(enum);TRUE_VALUES.include?(enum);end
|
59
|
+
|
60
|
+
# find shortened string value in allowed symbol list
|
61
|
+
def self.get_from_list(shortval,descr,allowed_values)
|
62
|
+
# we accept shortcuts
|
63
|
+
matching_exact=allowed_values.select{|i| i.to_s.eql?(shortval)}
|
64
|
+
return matching_exact.first if matching_exact.length == 1
|
65
|
+
matching=allowed_values.select{|i| i.to_s.start_with?(shortval)}
|
66
|
+
raise cli_bad_arg("unknown value for #{descr}: #{shortval}",allowed_values) if matching.empty?
|
67
|
+
raise cli_bad_arg("ambigous shortcut for #{descr}: #{shortval}",matching) unless matching.length.eql?(1)
|
68
|
+
return enum_to_bool(matching.first) if allowed_values.eql?(BOOLEAN_VALUES)
|
69
|
+
return matching.first
|
70
|
+
end
|
71
|
+
|
72
|
+
def self.cli_bad_arg(error_msg,choices)
|
73
|
+
return CliBadArgument.new(error_msg+"\nUse:\n"+choices.map{|c| "- #{c.to_s}\n"}.sort.join(''))
|
74
|
+
end
|
75
|
+
|
76
|
+
attr_reader :parser
|
77
|
+
attr_accessor :ask_missing_mandatory
|
78
|
+
attr_accessor :ask_missing_optional
|
79
|
+
|
80
|
+
#
|
81
|
+
def initialize(program_name,argv,app_banner)
|
82
|
+
# command line values not starting with '-'
|
83
|
+
@unprocessed_cmd_line_arguments=[]
|
84
|
+
# command line values starting with '-'
|
85
|
+
@unprocessed_cmd_line_options=[]
|
86
|
+
# a copy of all initial options
|
87
|
+
@initial_cli_options=[]
|
88
|
+
# option description: key = option symbol, value=hash, :type, :accessor, :value, :accepted
|
89
|
+
@declared_options={}
|
90
|
+
# do we ask missing options and arguments to user ?
|
91
|
+
@ask_missing_mandatory=false # STDIN.isatty
|
92
|
+
# ask optional options if not provided and in interactive
|
93
|
+
@ask_missing_optional=false
|
94
|
+
# those must be set before parse, parse consumes those defined only
|
95
|
+
@unprocessed_defaults=[]
|
96
|
+
@unprocessed_env=[]
|
97
|
+
# Note: was initially inherited but it is prefered to have specific methods
|
98
|
+
@parser=OptionParser.new
|
99
|
+
@parser.program_name=program_name
|
100
|
+
@parser.banner=app_banner
|
101
|
+
# options can also be provided by env vars : --param-name -> ASLMCLI_PARAM_NAME
|
102
|
+
env_prefix=program_name.upcase+OPTION_SEP_NAME
|
103
|
+
ENV.each do |k,v|
|
104
|
+
if k.start_with?(env_prefix)
|
105
|
+
@unprocessed_env.push([k[env_prefix.length..-1].downcase.to_sym,v])
|
106
|
+
end
|
107
|
+
end
|
108
|
+
Log.log.debug("env=#{@unprocessed_env}".red)
|
109
|
+
# banner is empty when help is generated for every plugin
|
110
|
+
unless app_banner.empty?
|
111
|
+
@parser.separator("")
|
112
|
+
@parser.separator("OPTIONS: global")
|
113
|
+
self.set_obj_attr(:interactive,self,:ask_missing_mandatory)
|
114
|
+
self.set_obj_attr(:ask_options,self,:ask_missing_optional)
|
115
|
+
self.add_opt_boolean(:interactive,"use interactive input of missing params")
|
116
|
+
self.add_opt_boolean(:ask_options,"ask even optional options")
|
117
|
+
self.parse_options!
|
118
|
+
end
|
119
|
+
@unprocessed_cmd_line_options=[]
|
120
|
+
@unprocessed_cmd_line_arguments=[]
|
121
|
+
process_options=true
|
122
|
+
while !argv.empty?
|
123
|
+
value=argv.shift
|
124
|
+
if process_options and value.start_with?('-')
|
125
|
+
if value.eql?('--')
|
126
|
+
process_options=false
|
127
|
+
else
|
128
|
+
@unprocessed_cmd_line_options.push(value)
|
129
|
+
end
|
130
|
+
else
|
131
|
+
@unprocessed_cmd_line_arguments.push(value)
|
132
|
+
end
|
133
|
+
end
|
134
|
+
@initial_cli_options=@unprocessed_cmd_line_options.dup
|
135
|
+
Log.log.debug("add_cmd_line_options:commands/args=#{@unprocessed_cmd_line_arguments},options=#{@unprocessed_cmd_line_options}".red)
|
136
|
+
end
|
137
|
+
|
138
|
+
def get_interactive(type,descr,expected=:single)
|
139
|
+
if !@ask_missing_mandatory
|
140
|
+
if expected.is_a?(Array)
|
141
|
+
raise self.class.cli_bad_arg("missing: #{descr}",expected)
|
142
|
+
end
|
143
|
+
raise CliBadArgument,"missing argument (#{expected}): #{descr}"
|
144
|
+
end
|
145
|
+
result=nil
|
146
|
+
# ask interactively
|
147
|
+
case expected
|
148
|
+
when :multiple
|
149
|
+
result=[]
|
150
|
+
puts " (one per line, end with empty line)"
|
151
|
+
loop do
|
152
|
+
print "#{type}: #{descr}> "
|
153
|
+
entry=STDIN.gets.chomp
|
154
|
+
break if entry.empty?
|
155
|
+
result.push(ExtendedValue.instance.evaluate(entry))
|
156
|
+
end
|
157
|
+
when :single
|
158
|
+
print "#{type}: #{descr}> "
|
159
|
+
result=ExtendedValue.instance.evaluate(STDIN.gets.chomp)
|
160
|
+
else # one fixed
|
161
|
+
print "#{expected.join(' ')}\n#{type}: #{descr}> "
|
162
|
+
result=self.class.get_from_list(STDIN.gets.chomp,descr,expected)
|
163
|
+
end
|
164
|
+
return result
|
165
|
+
end
|
166
|
+
|
167
|
+
def get_next_command(command_list); return get_next_argument('command',command_list); end
|
168
|
+
|
169
|
+
# @param expected is
|
170
|
+
# - Array of allowed value (single value)
|
171
|
+
# - :multiple for remaining values
|
172
|
+
# - :single for a single unconstrained value
|
173
|
+
# @param is_type : :mandatory or :optional
|
174
|
+
# @return value, list or nil
|
175
|
+
def get_next_argument(descr,expected=:single,is_type=:mandatory)
|
176
|
+
result=nil
|
177
|
+
if !@unprocessed_cmd_line_arguments.empty?
|
178
|
+
# there are values
|
179
|
+
case expected
|
180
|
+
when :single
|
181
|
+
result=ExtendedValue.instance.evaluate(@unprocessed_cmd_line_arguments.shift)
|
182
|
+
when :multiple
|
183
|
+
result = @unprocessed_cmd_line_arguments.shift(@unprocessed_cmd_line_arguments.length).map{|v|ExtendedValue.instance.evaluate(v)}
|
184
|
+
# if expecting list and only one arg of type array : it is the list
|
185
|
+
if result.length.eql?(1) and result.first.is_a?(Array)
|
186
|
+
result=result.first
|
187
|
+
end
|
188
|
+
else
|
189
|
+
result=self.class.get_from_list(@unprocessed_cmd_line_arguments.shift,descr,expected)
|
190
|
+
end
|
191
|
+
else
|
192
|
+
# no value provided
|
193
|
+
if is_type.eql?(:mandatory)
|
194
|
+
result=get_interactive(:argument,descr,expected)
|
195
|
+
end
|
196
|
+
end
|
197
|
+
Log.log.debug("#{descr}=#{result}")
|
198
|
+
return result
|
199
|
+
end
|
200
|
+
|
201
|
+
# declare option of type :accessor, or :value
|
202
|
+
def declare_option(option_symbol,type)
|
203
|
+
Log.log.debug("declare_option: #{option_symbol}: #{type}: skip=#{@declared_options.has_key?(option_symbol)}".green)
|
204
|
+
if @declared_options.has_key?(option_symbol)
|
205
|
+
raise "INTERNAL ERROR: option #{option_symbol} already declared. only accessor can be redeclared and ignored" unless @declared_options[option_symbol][:type].eql?(:accessor)
|
206
|
+
return
|
207
|
+
end
|
208
|
+
@declared_options[option_symbol]={:type=>type}
|
209
|
+
end
|
210
|
+
|
211
|
+
# define option with handler
|
212
|
+
def set_obj_attr(option_symbol,object,attr_symb,default_value=nil)
|
213
|
+
Log.log.debug("set attr obj #{option_symbol} (#{object},#{attr_symb})")
|
214
|
+
declare_option(option_symbol,:accessor)
|
215
|
+
@declared_options[option_symbol][:accessor]=AttrAccessor.new(object,attr_symb)
|
216
|
+
set_option(option_symbol,default_value,"default obj attr") if !default_value.nil?
|
217
|
+
end
|
218
|
+
|
219
|
+
# set an option value by name, either store value or call handler
|
220
|
+
def set_option(option_symbol,value,where="default")
|
221
|
+
if ! @declared_options.has_key?(option_symbol)
|
222
|
+
Log.log.debug("set unknown option: #{option_symbol}")
|
223
|
+
raise "ERROR"
|
224
|
+
#declare_option(option_symbol)
|
225
|
+
end
|
226
|
+
value=ExtendedValue.instance.evaluate(value)
|
227
|
+
Log.log.debug("set_option(#{where}) #{option_symbol}=#{value}")
|
228
|
+
if @declared_options[option_symbol][:values].eql?(BOOLEAN_VALUES)
|
229
|
+
value=enum_to_bool(value)
|
230
|
+
end
|
231
|
+
Log.log.debug("set #{option_symbol}=#{value} (#{@declared_options[option_symbol][:type]}) : #{where}".blue)
|
232
|
+
case @declared_options[option_symbol][:type]
|
233
|
+
when :accessor
|
234
|
+
@declared_options[option_symbol][:accessor].value=value
|
235
|
+
when :value
|
236
|
+
@declared_options[option_symbol][:value]=value
|
237
|
+
else # nil or other
|
238
|
+
raise "error"
|
239
|
+
end
|
240
|
+
end
|
241
|
+
|
242
|
+
# get an option value by name
|
243
|
+
# either return value or call handler, can return nil
|
244
|
+
# ask interactively if requested/required
|
245
|
+
def get_option(option_symbol,is_type=:optional)
|
246
|
+
result=nil
|
247
|
+
if @declared_options.has_key?(option_symbol)
|
248
|
+
case @declared_options[option_symbol][:type]
|
249
|
+
when :accessor
|
250
|
+
result=@declared_options[option_symbol][:accessor].value
|
251
|
+
when :value
|
252
|
+
result=@declared_options[option_symbol][:value]
|
253
|
+
else
|
254
|
+
raise "unknown type"
|
255
|
+
end
|
256
|
+
Log.log.debug("get #{option_symbol} (#{@declared_options[option_symbol][:type]}) : #{result}")
|
257
|
+
end
|
258
|
+
Log.log.debug("interactive=#{@ask_missing_mandatory}")
|
259
|
+
if result.nil?
|
260
|
+
if !@ask_missing_mandatory
|
261
|
+
if is_type.eql?(:mandatory)
|
262
|
+
raise CliBadArgument,"Missing mandatory option: #{option_symbol}"
|
263
|
+
end
|
264
|
+
else # ask_missing_mandatory
|
265
|
+
if @ask_missing_optional or is_type.eql?(:mandatory)
|
266
|
+
expected=:single
|
267
|
+
#print "please enter: #{option_symbol.to_s}"
|
268
|
+
if @declared_options.has_key?(option_symbol) and @declared_options[option_symbol].has_key?(:values)
|
269
|
+
expected=@declared_options[option_symbol][:values]
|
270
|
+
end
|
271
|
+
result=get_interactive(:option,option_symbol.to_s,expected)
|
272
|
+
set_option(option_symbol,result,"interactive")
|
273
|
+
end
|
274
|
+
end
|
275
|
+
end
|
276
|
+
return result
|
277
|
+
end
|
278
|
+
|
279
|
+
# param must be hash
|
280
|
+
def add_option_preset(preset_hash,op=:push)
|
281
|
+
Log.log.debug("add_option_preset=#{preset_hash}")
|
282
|
+
raise "internal error: setting default with no hash: #{preset_hash.class}" if !preset_hash.is_a?(Hash)
|
283
|
+
# incremental override
|
284
|
+
preset_hash.each{|k,v|@unprocessed_defaults.send(op,[k.to_sym,v])}
|
285
|
+
end
|
286
|
+
|
287
|
+
# generate command line option from option symbol
|
288
|
+
def symbol_to_option(symbol,opt_val)
|
289
|
+
result='--'+symbol.to_s.gsub(OPTION_SEP_NAME,OPTION_SEP_LINE)
|
290
|
+
result=result+'='+opt_val unless opt_val.nil?
|
291
|
+
return result
|
292
|
+
end
|
293
|
+
|
294
|
+
def highlight_current(value)
|
295
|
+
STDOUT.isatty ? value.to_s.red.bold : "[#{value}]"
|
296
|
+
end
|
297
|
+
|
298
|
+
# define an option with restricted values
|
299
|
+
def add_opt_list(option_symbol,values,help,*on_args)
|
300
|
+
declare_option(option_symbol,:value)
|
301
|
+
Log.log.debug("add_opt_list #{option_symbol}")
|
302
|
+
on_args.unshift(symbol_to_option(option_symbol,'ENUM'))
|
303
|
+
# this option value must be a symbol
|
304
|
+
@declared_options[option_symbol][:values]=values
|
305
|
+
value=get_option(option_symbol)
|
306
|
+
help_values=values.map{|i|i.eql?(value)?highlight_current(i):i}.join(', ')
|
307
|
+
if values.eql?(BOOLEAN_VALUES)
|
308
|
+
help_values=BOOLEAN_SIMPLE.map{|i|((i.eql?(:yes) and value) or (i.eql?(:no) and not value))?highlight_current(i):i}.join(', ')
|
309
|
+
end
|
310
|
+
on_args.push(values)
|
311
|
+
on_args.push("#{help}: #{help_values}")
|
312
|
+
Log.log.debug("on_args=#{on_args}")
|
313
|
+
@parser.on(*on_args){|v|set_option(option_symbol,self.class.get_from_list(v.to_s,help,values),"cmdline")}
|
314
|
+
end
|
315
|
+
|
316
|
+
def add_opt_boolean(option_symbol,help,*on_args)
|
317
|
+
add_opt_list(option_symbol,BOOLEAN_VALUES,help,*on_args)
|
318
|
+
end
|
319
|
+
|
320
|
+
# define an option with open values
|
321
|
+
def add_opt_simple(option_symbol,*on_args)
|
322
|
+
declare_option(option_symbol,:value)
|
323
|
+
Log.log.debug("add_opt_simple #{option_symbol}")
|
324
|
+
on_args.unshift(symbol_to_option(option_symbol,"VALUE"))
|
325
|
+
Log.log.debug("on_args=#{on_args}")
|
326
|
+
@parser.on(*on_args) { |v| set_option(option_symbol,v,"cmdline") }
|
327
|
+
end
|
328
|
+
|
329
|
+
# define an option with date format
|
330
|
+
def add_opt_date(option_symbol,*on_args)
|
331
|
+
declare_option(option_symbol,:value)
|
332
|
+
Log.log.debug("add_opt_date #{option_symbol}")
|
333
|
+
on_args.unshift(symbol_to_option(option_symbol,"DATE"))
|
334
|
+
Log.log.debug("on_args=#{on_args}")
|
335
|
+
@parser.on(*on_args) do |v|
|
336
|
+
case v
|
337
|
+
when 'now'; set_option(option_symbol,Manager.time_to_string(Time.now),"cmdline")
|
338
|
+
when /^-([0-9]+)h/; set_option(option_symbol,Manager.time_to_string(Time.now-$1.to_i*3600),"cmdline")
|
339
|
+
else set_option(option_symbol,v,"cmdline")
|
340
|
+
end
|
341
|
+
end
|
342
|
+
end
|
343
|
+
|
344
|
+
# define an option without value
|
345
|
+
def add_opt_switch(option_symbol,*on_args,&block)
|
346
|
+
Log.log.debug("add_opt_on #{option_symbol}")
|
347
|
+
on_args.unshift(symbol_to_option(option_symbol,nil))
|
348
|
+
Log.log.debug("on_args=#{on_args}")
|
349
|
+
@parser.on(*on_args,&block)
|
350
|
+
end
|
351
|
+
|
352
|
+
# check if there were unprocessed values to generate error
|
353
|
+
def command_or_arg_empty?
|
354
|
+
return @unprocessed_cmd_line_arguments.empty?
|
355
|
+
end
|
356
|
+
|
357
|
+
# unprocessed options or arguments ?
|
358
|
+
def final_errors
|
359
|
+
result=[]
|
360
|
+
result.push("unprocessed options: #{@unprocessed_cmd_line_options}") unless @unprocessed_cmd_line_options.empty?
|
361
|
+
result.push("unprocessed values: #{@unprocessed_cmd_line_arguments}") unless @unprocessed_cmd_line_arguments.empty?
|
362
|
+
return result
|
363
|
+
end
|
364
|
+
|
365
|
+
# get all original options on command line used to generate a config in config file
|
366
|
+
def get_options_table(remove_from_remaining=true)
|
367
|
+
result={}
|
368
|
+
@initial_cli_options.each do |optionval|
|
369
|
+
case optionval
|
370
|
+
when /^--([^=]+)$/
|
371
|
+
# ignore
|
372
|
+
when /^--([^=]+)=(.*)$/
|
373
|
+
name=$1
|
374
|
+
value=$2
|
375
|
+
name.gsub!(OPTION_SEP_LINE,OPTION_SEP_NAME)
|
376
|
+
value=ExtendedValue.instance.evaluate(value)
|
377
|
+
Log.log.debug("option #{name}=#{value}")
|
378
|
+
result[name]=value
|
379
|
+
@unprocessed_cmd_line_options.delete(optionval) if remove_from_remaining
|
380
|
+
else
|
381
|
+
raise CliBadArgument,"wrong option format: #{optionval}"
|
382
|
+
end
|
383
|
+
end
|
384
|
+
return result
|
385
|
+
end
|
386
|
+
|
387
|
+
# return options as taken from config file and command line just before command execution
|
388
|
+
def declared_options(all=true)
|
389
|
+
return @declared_options.keys.inject({}) do |h,option_symb|
|
390
|
+
v=get_option(option_symb)
|
391
|
+
h[option_symb.to_s]=v if all or !v.nil?
|
392
|
+
h
|
393
|
+
end
|
394
|
+
end
|
395
|
+
|
396
|
+
def apply_options_preset(preset,where,force=false)
|
397
|
+
unprocessed=[]
|
398
|
+
preset.each do |pair|
|
399
|
+
k,v=*pair
|
400
|
+
if @declared_options.has_key?(k)
|
401
|
+
# constrained parameters as string are revert to symbol
|
402
|
+
if @declared_options[k].has_key?(:values) and v.is_a?(String)
|
403
|
+
v=self.class.get_from_list(v,k.to_s+" in #{where}",@declared_options[k][:values])
|
404
|
+
end
|
405
|
+
set_option(k,v,where)
|
406
|
+
else
|
407
|
+
unprocessed.push(pair)
|
408
|
+
end
|
409
|
+
end
|
410
|
+
# keep only unprocessed values for next parse
|
411
|
+
preset.clear
|
412
|
+
preset.push(*unprocessed)
|
413
|
+
end
|
414
|
+
|
415
|
+
# removes already known options from the list
|
416
|
+
def parse_options!
|
417
|
+
Log.log.debug("parse_options!".red)
|
418
|
+
# first conf file, then env var
|
419
|
+
apply_options_preset(@unprocessed_defaults,"file")
|
420
|
+
apply_options_preset(@unprocessed_env,"env")
|
421
|
+
# command line override
|
422
|
+
unknown_options=[]
|
423
|
+
begin
|
424
|
+
# remove known options one by one, exception if unknown
|
425
|
+
Log.log.debug("before parse".red)
|
426
|
+
@parser.parse!(@unprocessed_cmd_line_options)
|
427
|
+
Log.log.debug("After parse".red)
|
428
|
+
rescue OptionParser::InvalidOption => e
|
429
|
+
Log.log.debug("InvalidOption #{e}".red)
|
430
|
+
# save for later processing
|
431
|
+
unknown_options.push(e.args.first)
|
432
|
+
retry
|
433
|
+
end
|
434
|
+
Log.log.debug("remains: #{unknown_options}")
|
435
|
+
# set unprocessed options for next time
|
436
|
+
@unprocessed_cmd_line_options=unknown_options
|
437
|
+
end
|
438
|
+
end
|
439
|
+
end
|
440
|
+
end
|
@@ -0,0 +1,90 @@
|
|
1
|
+
module Aspera
|
2
|
+
module Cli
|
3
|
+
# base class for plugins modules
|
4
|
+
class Plugin
|
5
|
+
GLOBAL_OPS=[:create,:list]
|
6
|
+
INSTANCE_OPS=[:modify,:delete,:show]
|
7
|
+
ALL_OPS=[GLOBAL_OPS,INSTANCE_OPS].flatten
|
8
|
+
#private_constant :GLOBAL_OPS,:INSTANCE_OPS,:ALL_OPS
|
9
|
+
|
10
|
+
@@done=false
|
11
|
+
|
12
|
+
def initialize(env)
|
13
|
+
@agents=env
|
14
|
+
raise StandardError,"execute_action shall be redefined by subclass #{self.class}" unless respond_to?(:execute_action)
|
15
|
+
raise StandardError,"ACTIONS shall be redefined by subclass" unless self.class.constants.include?(:ACTIONS)
|
16
|
+
unless env[:skip_option_header]
|
17
|
+
self.options.parser.separator ""
|
18
|
+
self.options.parser.separator "COMMAND: #{self.class.name.split('::').last.downcase}"
|
19
|
+
self.options.parser.separator "SUBCOMMANDS: #{self.class.const_get(:ACTIONS).map{ |p| p.to_s}.join(' ')}"
|
20
|
+
self.options.parser.separator "OPTIONS:"
|
21
|
+
end
|
22
|
+
unless @@done
|
23
|
+
self.options.add_opt_simple(:value,"extended value for create, update, list filter")
|
24
|
+
self.options.add_opt_simple(:property,"name of property to set")
|
25
|
+
self.options.add_opt_simple(:id,"resource identifier (#{INSTANCE_OPS.join(",")})")
|
26
|
+
self.options.parse_options!
|
27
|
+
@@done=true
|
28
|
+
end
|
29
|
+
end
|
30
|
+
|
31
|
+
def entity_command(command,rest_api,res_class_path,display_fields,id_symb,id_default=nil,subkey=false)
|
32
|
+
if INSTANCE_OPS.include?(command)
|
33
|
+
begin
|
34
|
+
one_res_id=self.options.get_option(id_symb,:mandatory)
|
35
|
+
rescue => e
|
36
|
+
raise e if id_default.nil?
|
37
|
+
one_res_id=id_default
|
38
|
+
end
|
39
|
+
one_res_path="#{res_class_path}/#{one_res_id}"
|
40
|
+
end
|
41
|
+
# parameters mandatory for create/modify
|
42
|
+
if [:create,:modify].include?(command)
|
43
|
+
parameters=self.options.get_option(:value,:mandatory)
|
44
|
+
end
|
45
|
+
# parameters optional for list
|
46
|
+
if [:list].include?(command)
|
47
|
+
parameters=self.options.get_option(:value,:optional)
|
48
|
+
end
|
49
|
+
case command
|
50
|
+
when :create
|
51
|
+
return {:type => :single_object, :data=>rest_api.create(res_class_path,parameters)[:data], :fields=>display_fields}
|
52
|
+
when :show
|
53
|
+
return {:type => :single_object, :data=>rest_api.read(one_res_path)[:data], :fields=>display_fields}
|
54
|
+
when :list
|
55
|
+
resp=rest_api.read(res_class_path,parameters)
|
56
|
+
data=resp[:data]
|
57
|
+
if resp[:http]['Content-Type'].start_with?('application/vnd.api+json')
|
58
|
+
data=resp[:data][res_class_path]
|
59
|
+
end
|
60
|
+
data=data[res_class_path] if subkey
|
61
|
+
return {:type => :object_list, :data=>data, :fields=>display_fields}
|
62
|
+
when :modify
|
63
|
+
property=self.options.get_option(:property,:optional)
|
64
|
+
parameters={property => parameters} unless property.nil?
|
65
|
+
rest_api.update(one_res_path,parameters)
|
66
|
+
return Main.result_status('modified')
|
67
|
+
when :delete
|
68
|
+
rest_api.delete(one_res_path)
|
69
|
+
return Main.result_status("deleted")
|
70
|
+
end
|
71
|
+
end
|
72
|
+
|
73
|
+
# implement generic rest operations on given resource path
|
74
|
+
def entity_action(rest_api,res_class_path,display_fields,id_symb,id_default=nil,subkey=false)
|
75
|
+
#res_name=res_class_path.gsub(%r{^.*/},'').gsub(%r{s$},'').gsub('_',' ')
|
76
|
+
command=self.options.get_next_command(ALL_OPS)
|
77
|
+
return entity_command(command,rest_api,res_class_path,display_fields,id_symb,id_default,subkey)
|
78
|
+
end
|
79
|
+
|
80
|
+
def options;@agents[:options];end
|
81
|
+
|
82
|
+
def transfer;@agents[:transfer];end
|
83
|
+
|
84
|
+
def config;return @agents[:config];end
|
85
|
+
|
86
|
+
def format;return @agents[:formater];end
|
87
|
+
|
88
|
+
end # Plugin
|
89
|
+
end # Cli
|
90
|
+
end # Aspera
|