aspera-cli 4.0.0.pre1
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.
- 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
|