aspera-cli 4.4.0 → 4.7.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/README.md +2095 -1503
- data/bin/ascli +2 -1
- data/bin/asession +4 -5
- data/docs/test_env.conf +3 -0
- data/examples/aoc.rb +4 -3
- data/examples/faspex4.rb +25 -25
- data/examples/proxy.pac +1 -1
- data/examples/transfer.rb +17 -17
- data/lib/aspera/aoc.rb +238 -185
- data/lib/aspera/ascmd.rb +93 -83
- data/lib/aspera/ats_api.rb +11 -10
- data/lib/aspera/cli/basic_auth_plugin.rb +13 -14
- data/lib/aspera/cli/extended_value.rb +42 -33
- data/lib/aspera/cli/formater.rb +142 -108
- data/lib/aspera/cli/info.rb +17 -0
- data/lib/aspera/cli/listener/line_dump.rb +3 -2
- data/lib/aspera/cli/listener/logger.rb +2 -1
- data/lib/aspera/cli/listener/progress.rb +16 -18
- data/lib/aspera/cli/listener/progress_multi.rb +18 -21
- data/lib/aspera/cli/main.rb +173 -149
- data/lib/aspera/cli/manager.rb +163 -168
- data/lib/aspera/cli/plugin.rb +43 -31
- data/lib/aspera/cli/plugins/alee.rb +6 -6
- data/lib/aspera/cli/plugins/aoc.rb +405 -370
- data/lib/aspera/cli/plugins/ats.rb +86 -79
- data/lib/aspera/cli/plugins/bss.rb +14 -16
- data/lib/aspera/cli/plugins/config.rb +580 -362
- data/lib/aspera/cli/plugins/console.rb +23 -19
- data/lib/aspera/cli/plugins/cos.rb +18 -18
- data/lib/aspera/cli/plugins/faspex.rb +201 -158
- data/lib/aspera/cli/plugins/faspex5.rb +80 -57
- data/lib/aspera/cli/plugins/node.rb +183 -166
- data/lib/aspera/cli/plugins/orchestrator.rb +71 -67
- data/lib/aspera/cli/plugins/preview.rb +92 -96
- data/lib/aspera/cli/plugins/server.rb +79 -75
- data/lib/aspera/cli/plugins/shares.rb +35 -19
- data/lib/aspera/cli/plugins/sync.rb +20 -22
- data/lib/aspera/cli/transfer_agent.rb +76 -113
- data/lib/aspera/cli/version.rb +2 -1
- data/lib/aspera/colors.rb +35 -27
- data/lib/aspera/command_line_builder.rb +48 -34
- data/lib/aspera/cos_node.rb +29 -21
- data/lib/aspera/data_repository.rb +3 -2
- data/lib/aspera/environment.rb +50 -45
- data/lib/aspera/fasp/{manager.rb → agent_base.rb} +28 -25
- data/lib/aspera/fasp/{connect.rb → agent_connect.rb} +52 -43
- data/lib/aspera/fasp/{local.rb → agent_direct.rb} +58 -72
- data/lib/aspera/fasp/{http_gw.rb → agent_httpgw.rb} +37 -43
- data/lib/aspera/fasp/{node.rb → agent_node.rb} +35 -16
- data/lib/aspera/fasp/agent_trsdk.rb +104 -0
- data/lib/aspera/fasp/error.rb +2 -1
- data/lib/aspera/fasp/error_info.rb +68 -52
- data/lib/aspera/fasp/installation.rb +152 -124
- data/lib/aspera/fasp/listener.rb +1 -0
- data/lib/aspera/fasp/parameters.rb +87 -92
- data/lib/aspera/fasp/parameters.yaml +305 -249
- data/lib/aspera/fasp/resume_policy.rb +11 -14
- data/lib/aspera/fasp/transfer_spec.rb +26 -0
- data/lib/aspera/fasp/uri.rb +22 -21
- data/lib/aspera/faspex_gw.rb +55 -89
- data/lib/aspera/hash_ext.rb +4 -3
- data/lib/aspera/id_generator.rb +8 -7
- data/lib/aspera/keychain/encrypted_hash.rb +121 -0
- data/lib/aspera/keychain/macos_security.rb +90 -0
- data/lib/aspera/log.rb +55 -37
- data/lib/aspera/nagios.rb +13 -12
- data/lib/aspera/node.rb +30 -25
- data/lib/aspera/oauth.rb +175 -226
- data/lib/aspera/open_application.rb +4 -3
- data/lib/aspera/persistency_action_once.rb +6 -6
- data/lib/aspera/persistency_folder.rb +5 -9
- data/lib/aspera/preview/file_types.rb +6 -5
- data/lib/aspera/preview/generator.rb +25 -24
- data/lib/aspera/preview/options.rb +16 -14
- data/lib/aspera/preview/utils.rb +98 -98
- data/lib/aspera/{proxy_auto_config.erb.js → proxy_auto_config.js} +23 -31
- data/lib/aspera/proxy_auto_config.rb +111 -20
- data/lib/aspera/rest.rb +154 -135
- data/lib/aspera/rest_call_error.rb +2 -2
- data/lib/aspera/rest_error_analyzer.rb +23 -25
- data/lib/aspera/rest_errors_aspera.rb +15 -14
- data/lib/aspera/ssh.rb +12 -10
- data/lib/aspera/sync.rb +42 -41
- data/lib/aspera/temp_file_manager.rb +18 -14
- data/lib/aspera/timer_limiter.rb +2 -1
- data/lib/aspera/uri_reader.rb +7 -5
- data/lib/aspera/web_auth.rb +79 -76
- metadata +116 -29
- data/docs/Makefile +0 -66
- data/docs/README.erb.md +0 -3973
- data/docs/README.md +0 -13
- data/docs/diagrams.txt +0 -49
- data/docs/doc_tools.rb +0 -58
- data/lib/aspera/api_detector.rb +0 -60
- data/lib/aspera/cli/plugins/shares2.rb +0 -114
- data/lib/aspera/secrets.rb +0 -20
data/lib/aspera/cli/formater.rb
CHANGED
|
@@ -1,7 +1,5 @@
|
|
|
1
|
-
#
|
|
1
|
+
# frozen_string_literal: true
|
|
2
2
|
require 'terminal-table'
|
|
3
|
-
|
|
4
|
-
#require 'fileutils'
|
|
5
3
|
require 'yaml'
|
|
6
4
|
require 'pp'
|
|
7
5
|
|
|
@@ -12,38 +10,96 @@ module Aspera
|
|
|
12
10
|
FIELDS_ALL='ALL'
|
|
13
11
|
FIELDS_DEFAULT='DEF'
|
|
14
12
|
# supported output formats
|
|
15
|
-
DISPLAY_FORMATS
|
|
13
|
+
DISPLAY_FORMATS=%i[table ruby json jsonpp yaml csv nagios]
|
|
16
14
|
# user output levels
|
|
17
15
|
DISPLAY_LEVELS=[:info,:data,:error]
|
|
18
16
|
CSV_RECORD_SEPARATOR="\n"
|
|
19
|
-
CSV_FIELD_SEPARATOR=
|
|
17
|
+
CSV_FIELD_SEPARATOR=','
|
|
18
|
+
HIDDEN_PASSWORD='🔑'
|
|
19
|
+
SECRET_KEYWORDS=%w[password secret private_key]
|
|
20
|
+
|
|
21
|
+
private_constant :FIELDS_ALL,:FIELDS_DEFAULT,:DISPLAY_FORMATS,:DISPLAY_LEVELS,:CSV_RECORD_SEPARATOR,:CSV_FIELD_SEPARATOR,:HIDDEN_PASSWORD
|
|
20
22
|
|
|
21
|
-
|
|
22
|
-
|
|
23
|
+
class<<self
|
|
24
|
+
# @param source [Hash] hash to modify
|
|
25
|
+
# @param keep_last [bool]
|
|
26
|
+
def flatten_object(source,keep_last)
|
|
27
|
+
newval={}
|
|
28
|
+
flatten_sub_hash_rec(source,keep_last,'',newval)
|
|
29
|
+
source.clear
|
|
30
|
+
source.merge!(newval)
|
|
31
|
+
end
|
|
23
32
|
|
|
33
|
+
# recursive function to modify a hash
|
|
34
|
+
# @param source [Hash] to be modified
|
|
35
|
+
# @param keep_last [bool] truer if last level is not
|
|
36
|
+
# @param prefix [String] true if last level is not
|
|
37
|
+
# @param dest [Hash] new hash flattened
|
|
38
|
+
def flatten_sub_hash_rec(source,keep_last,prefix,dest)
|
|
39
|
+
#is_simple_hash=source.is_a?(Hash) and source.values.inject(true){|m,v| xxx=!v.respond_to?(:each) and m;puts("->#{xxx}>#{v.respond_to?(:each)} #{v}-");xxx}
|
|
40
|
+
is_simple_hash=false
|
|
41
|
+
Log.log.debug("(#{keep_last})[#{is_simple_hash}] -#{source.values}- \n-#{source}-")
|
|
42
|
+
return source if keep_last && is_simple_hash
|
|
43
|
+
source.each do |k,v|
|
|
44
|
+
if v.is_a?(Hash) && (!keep_last || !is_simple_hash)
|
|
45
|
+
flatten_sub_hash_rec(v,keep_last,prefix+k.to_s+'.',dest)
|
|
46
|
+
else
|
|
47
|
+
dest[prefix+k.to_s]=v
|
|
48
|
+
end
|
|
49
|
+
end
|
|
50
|
+
return nil
|
|
51
|
+
end
|
|
52
|
+
|
|
53
|
+
# special for Aspera on Cloud display node
|
|
54
|
+
# {"param" => [{"name"=>"foo","value"=>"bar"}]} will be expanded to {"param.foo" : "bar"}
|
|
55
|
+
def flatten_name_value_list(hash)
|
|
56
|
+
hash.keys.each do |k|
|
|
57
|
+
v=hash[k]
|
|
58
|
+
next unless v.is_a?(Array) && v.map(&:class).uniq.eql?([Hash]) && v.map(&:keys).flatten.sort.uniq.eql?(['name', 'value'])
|
|
59
|
+
v.each do |pair|
|
|
60
|
+
hash["#{k}.#{pair['name']}"]=pair['value']
|
|
61
|
+
end
|
|
62
|
+
hash.delete(k)
|
|
63
|
+
end
|
|
64
|
+
end
|
|
65
|
+
end
|
|
66
|
+
|
|
67
|
+
attr_accessor :option_flat_hash,:option_transpose_single,:option_format,:option_display,:option_fields,:option_table_style,:option_select,:option_show_secrets
|
|
68
|
+
|
|
69
|
+
# adds options but does not parse
|
|
24
70
|
def initialize(opt_mgr)
|
|
71
|
+
@option_format=:table
|
|
72
|
+
@option_display=:info
|
|
73
|
+
@option_fields=FIELDS_DEFAULT
|
|
74
|
+
@option_select=nil
|
|
75
|
+
@option_table_style=':.:'
|
|
25
76
|
@option_flat_hash=true
|
|
26
|
-
@
|
|
27
|
-
@
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
77
|
+
@option_transpose_single=true
|
|
78
|
+
@option_show_secrets=true
|
|
79
|
+
opt_mgr.set_obj_attr(:format,self,:option_format)
|
|
80
|
+
opt_mgr.set_obj_attr(:display,self,:option_display)
|
|
81
|
+
opt_mgr.set_obj_attr(:fields,self,:option_fields)
|
|
82
|
+
opt_mgr.set_obj_attr(:select,self,:option_select)
|
|
83
|
+
opt_mgr.set_obj_attr(:table_style,self,:option_table_style)
|
|
84
|
+
opt_mgr.set_obj_attr(:flat_hash,self,:option_flat_hash)
|
|
85
|
+
opt_mgr.set_obj_attr(:transpose_single,self,:option_transpose_single)
|
|
86
|
+
opt_mgr.set_obj_attr(:show_secrets,self,:option_show_secrets)
|
|
87
|
+
opt_mgr.add_opt_list(:format,DISPLAY_FORMATS,'output format')
|
|
88
|
+
opt_mgr.add_opt_list(:display,DISPLAY_LEVELS,'output only some information')
|
|
89
|
+
opt_mgr.add_opt_simple(:fields,"comma separated list of fields, or #{FIELDS_ALL}, or #{FIELDS_DEFAULT}")
|
|
90
|
+
opt_mgr.add_opt_simple(:select,'select only some items in lists, extended value: hash (column, value)')
|
|
91
|
+
opt_mgr.add_opt_simple(:table_style,'table display style')
|
|
92
|
+
opt_mgr.add_opt_boolean(:flat_hash,'display hash values as additional keys')
|
|
93
|
+
opt_mgr.add_opt_boolean(:transpose_single,'single object fields output vertically')
|
|
94
|
+
opt_mgr.add_opt_boolean(:show_secrets,'show secrets on command output')
|
|
38
95
|
end
|
|
39
96
|
|
|
40
97
|
# main output method
|
|
41
98
|
def display_message(message_level,message)
|
|
42
|
-
display_level=@opt_mgr.get_option(:display,:mandatory)
|
|
43
99
|
case message_level
|
|
44
|
-
when :info
|
|
45
|
-
when :data
|
|
46
|
-
when :error
|
|
100
|
+
when :info then $stdout.puts(message) if @option_display.eql?(:info)
|
|
101
|
+
when :data then $stdout.puts(message) unless @option_display.eql?(:error)
|
|
102
|
+
when :error then $stderr.puts(message)
|
|
47
103
|
else raise "wrong message_level:#{message_level}"
|
|
48
104
|
end
|
|
49
105
|
end
|
|
@@ -52,77 +108,51 @@ module Aspera
|
|
|
52
108
|
display_message(:info,status)
|
|
53
109
|
end
|
|
54
110
|
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
source.merge!(newval)
|
|
62
|
-
end
|
|
63
|
-
|
|
64
|
-
# recursive function to modify a hash
|
|
65
|
-
# @param source [Hash] to be modified
|
|
66
|
-
# @param keep_last [bool] truer if last level is not
|
|
67
|
-
# @param prefix [String] true if last level is not
|
|
68
|
-
# @param dest [Hash] new hash flattened
|
|
69
|
-
def self.flatten_sub_hash_rec(source,keep_last,prefix,dest)
|
|
70
|
-
#is_simple_hash=source.is_a?(Hash) and source.values.inject(true){|m,v| xxx=!v.respond_to?(:each) and m;puts("->#{xxx}>#{v.respond_to?(:each)} #{v}-");xxx}
|
|
71
|
-
is_simple_hash=false
|
|
72
|
-
Log.log.debug("(#{keep_last})[#{is_simple_hash}] -#{source.values}- \n-#{source}-")
|
|
73
|
-
return source if keep_last and is_simple_hash
|
|
74
|
-
source.each do |k,v|
|
|
75
|
-
if v.is_a?(Hash) and ( !keep_last or !is_simple_hash )
|
|
76
|
-
flatten_sub_hash_rec(v,keep_last,prefix+k.to_s+'.',dest)
|
|
77
|
-
else
|
|
78
|
-
dest[prefix+k.to_s]=v
|
|
111
|
+
def result_default_fields(results,table_rows_hash_val)
|
|
112
|
+
unless results[:fields].nil?
|
|
113
|
+
raise "internal error: [fields] must be Array, not #{results[:fields].class}" unless results[:fields].is_a?(Array)
|
|
114
|
+
if results[:fields].first.eql?(:all_but) && !table_rows_hash_val.empty?
|
|
115
|
+
filter=results[:fields][1..-1]
|
|
116
|
+
return table_rows_hash_val.first.keys.reject{|i|filter.include?(i)}
|
|
79
117
|
end
|
|
118
|
+
return results[:fields]
|
|
80
119
|
end
|
|
81
|
-
return
|
|
120
|
+
return ['empty'] if table_rows_hash_val.empty?
|
|
121
|
+
return table_rows_hash_val.first.keys
|
|
82
122
|
end
|
|
83
123
|
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
v=hash[k]
|
|
89
|
-
if v.is_a?(Array) and v.map{|i|i.class}.uniq.eql?([Hash]) and v.map{|i|i.keys}.flatten.sort.uniq.eql?(["name", "value"])
|
|
90
|
-
v.each do |pair|
|
|
91
|
-
hash["#{k}.#{pair["name"]}"]=pair["value"]
|
|
92
|
-
end
|
|
93
|
-
hash.delete(k)
|
|
94
|
-
end
|
|
95
|
-
end
|
|
124
|
+
def result_all_fields(_results,table_rows_hash_val)
|
|
125
|
+
raise 'internal error: must be array' unless table_rows_hash_val.is_a?(Array)
|
|
126
|
+
# get the list of all column names used in all lines, not just frst one, as all lines may have different columns
|
|
127
|
+
return table_rows_hash_val.each_with_object({}){|v,m|v.keys.each{|c|m[c]=true};}.keys
|
|
96
128
|
end
|
|
97
129
|
|
|
98
|
-
def
|
|
99
|
-
if
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
130
|
+
def deep_remove_secret(obj)
|
|
131
|
+
return if @option_show_secrets
|
|
132
|
+
case obj
|
|
133
|
+
when Array then obj.each{|i|deep_remove_secret(i)}
|
|
134
|
+
when Hash
|
|
135
|
+
obj.keys.each do |k|
|
|
136
|
+
next if %w[show_secrets log_secrets].any?{|kw|kw.eql?(k)}
|
|
137
|
+
if k.is_a?(String) && SECRET_KEYWORDS.any?{|kw|k.include?(kw)}
|
|
138
|
+
obj[k]=HIDDEN_PASSWORD
|
|
139
|
+
elsif obj[k].is_a?(Hash)
|
|
140
|
+
deep_remove_secret(obj[k])
|
|
141
|
+
end
|
|
106
142
|
end
|
|
107
143
|
end
|
|
108
144
|
end
|
|
109
145
|
|
|
110
|
-
def result_all_fields(results,table_rows_hash_val)
|
|
111
|
-
raise "internal error: must be array" unless table_rows_hash_val.is_a?(Array)
|
|
112
|
-
# get the list of all column names used in all lines, not just frst one, as all lines may have different columns
|
|
113
|
-
return table_rows_hash_val.inject({}){|m,v|v.keys.each{|c|m[c]=true};m}.keys
|
|
114
|
-
end
|
|
115
|
-
|
|
116
146
|
# this method displays the results, especially the table format
|
|
117
147
|
def display_results(results)
|
|
118
148
|
raise "INTERNAL ERROR, result must be Hash (got: #{results.class}: #{results})" unless results.is_a?(Hash)
|
|
119
|
-
raise
|
|
120
|
-
raise
|
|
149
|
+
raise 'INTERNAL ERROR, result must have type' unless results.has_key?(:type)
|
|
150
|
+
raise 'INTERNAL ERROR, result must have data' unless results.has_key?(:data) || [:empty,:nothing].include?(results[:type])
|
|
121
151
|
res_data=results[:data]
|
|
152
|
+
deep_remove_secret(res_data)
|
|
122
153
|
# comma separated list in string format
|
|
123
|
-
user_asked_fields_list_str=@
|
|
124
|
-
|
|
125
|
-
case display_format
|
|
154
|
+
user_asked_fields_list_str=@option_fields
|
|
155
|
+
case @option_format
|
|
126
156
|
when :nagios
|
|
127
157
|
Nagios.process(res_data)
|
|
128
158
|
when :ruby
|
|
@@ -134,6 +164,10 @@ module Aspera
|
|
|
134
164
|
when :yaml
|
|
135
165
|
display_message(:data,res_data.to_yaml)
|
|
136
166
|
when :table,:csv
|
|
167
|
+
if !@option_transpose_single && results[:type].eql?(:single_object)
|
|
168
|
+
results[:type]=:object_list
|
|
169
|
+
res_data=[res_data]
|
|
170
|
+
end
|
|
137
171
|
case results[:type]
|
|
138
172
|
when :object_list # goes to table display
|
|
139
173
|
raise "internal error: unexpected type: #{res_data.class}, expecting Array" unless res_data.is_a?(Array)
|
|
@@ -145,14 +179,15 @@ module Aspera
|
|
|
145
179
|
self.class.flatten_object(obj,results[:option_expand_last])
|
|
146
180
|
end
|
|
147
181
|
end
|
|
148
|
-
final_table_columns=
|
|
149
|
-
|
|
150
|
-
when
|
|
182
|
+
final_table_columns=
|
|
183
|
+
case user_asked_fields_list_str
|
|
184
|
+
when FIELDS_DEFAULT then result_default_fields(results,table_rows_hash_val)
|
|
185
|
+
when FIELDS_ALL then result_all_fields(results,table_rows_hash_val)
|
|
151
186
|
else
|
|
152
187
|
if user_asked_fields_list_str.start_with?('+')
|
|
153
188
|
result_default_fields(results,table_rows_hash_val).push(*user_asked_fields_list_str.gsub(/^\+/,'').split(','))
|
|
154
189
|
elsif user_asked_fields_list_str.start_with?('-')
|
|
155
|
-
result_default_fields(results,table_rows_hash_val).
|
|
190
|
+
result_default_fields(results,table_rows_hash_val).reject{|i| user_asked_fields_list_str.gsub(/^-/,'').split(',').include?(i)}
|
|
156
191
|
else
|
|
157
192
|
user_asked_fields_list_str.split(',')
|
|
158
193
|
end
|
|
@@ -165,13 +200,14 @@ module Aspera
|
|
|
165
200
|
self.class.flatten_object(res_data,results[:option_expand_last])
|
|
166
201
|
self.class.flatten_name_value_list(res_data)
|
|
167
202
|
end
|
|
168
|
-
asked_fields=
|
|
169
|
-
|
|
170
|
-
when
|
|
171
|
-
|
|
203
|
+
asked_fields=
|
|
204
|
+
case user_asked_fields_list_str
|
|
205
|
+
when FIELDS_DEFAULT then results[:fields]||res_data.keys
|
|
206
|
+
when FIELDS_ALL then res_data.keys
|
|
207
|
+
else user_asked_fields_list_str.split(',')
|
|
172
208
|
end
|
|
173
209
|
table_rows_hash_val=asked_fields.map { |i| { final_table_columns.first => i, final_table_columns.last => res_data[i] } }
|
|
174
|
-
when :value_list
|
|
210
|
+
when :value_list # goes to table display
|
|
175
211
|
# :value_list is a simple array of values, name of column provided in the :name
|
|
176
212
|
final_table_columns = [results[:name]]
|
|
177
213
|
table_rows_hash_val=res_data.map { |i| { results[:name] => i } }
|
|
@@ -179,7 +215,7 @@ module Aspera
|
|
|
179
215
|
display_message(:info,'empty')
|
|
180
216
|
return
|
|
181
217
|
when :nothing # no result expected
|
|
182
|
-
Log.log.debug(
|
|
218
|
+
Log.log.debug('no result expected')
|
|
183
219
|
return
|
|
184
220
|
when :status # no table
|
|
185
221
|
# :status displays a simple message
|
|
@@ -197,39 +233,37 @@ module Aspera
|
|
|
197
233
|
raise "unknown data type: #{results[:type]}"
|
|
198
234
|
end
|
|
199
235
|
# here we expect: table_rows_hash_val and final_table_columns
|
|
200
|
-
raise
|
|
236
|
+
raise 'no field specified' if final_table_columns.nil?
|
|
201
237
|
if table_rows_hash_val.empty?
|
|
202
|
-
display_message(:info,'empty'.gray) unless
|
|
238
|
+
display_message(:info,'empty'.gray) unless @option_format.eql?(:csv)
|
|
203
239
|
return
|
|
204
240
|
end
|
|
205
241
|
# convert to string with special function. here table_rows_hash_val is an array of hash
|
|
206
242
|
table_rows_hash_val=results[:textify].call(table_rows_hash_val) if results.has_key?(:textify)
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
filter.each{|k,v|table_rows_hash_val.select!{|i|i[k].eql?(v)}}
|
|
243
|
+
unless @option_select.nil? || (@option_select.respond_to?('empty?') && @option_select.empty?)
|
|
244
|
+
raise CliBadArgument,"expecting hash for select, have #{@option_select.class}: #{@option_select}" unless @option_select.is_a?(Hash)
|
|
245
|
+
@option_select.each{|k,v|table_rows_hash_val.select!{|i|i[k].eql?(v)}}
|
|
211
246
|
end
|
|
212
|
-
|
|
213
247
|
# convert data to string, and keep only display fields
|
|
214
248
|
final_table_rows=table_rows_hash_val.map { |r| final_table_columns.map { |c| r[c].to_s } }
|
|
215
249
|
# here : final_table_columns : list of column names
|
|
216
250
|
# here: final_table_rows : array of list of value
|
|
217
|
-
case
|
|
251
|
+
case @option_format
|
|
218
252
|
when :table
|
|
219
|
-
style=@
|
|
253
|
+
style=@option_table_style.chars
|
|
220
254
|
# display the table !
|
|
221
255
|
#display_message(:data,Text::Table.new(
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
256
|
+
#head: final_table_columns,
|
|
257
|
+
#rows: final_table_rows,
|
|
258
|
+
#horizontal_boundary: style[0],
|
|
259
|
+
#vertical_boundary: style[1],
|
|
260
|
+
#boundary_intersection: style[2]))
|
|
227
261
|
display_message(:data,Terminal::Table.new(
|
|
228
|
-
:
|
|
229
|
-
:
|
|
230
|
-
:
|
|
231
|
-
:
|
|
232
|
-
:
|
|
262
|
+
headings: final_table_columns,
|
|
263
|
+
rows: final_table_rows,
|
|
264
|
+
border_x: style[0],
|
|
265
|
+
border_y: style[1],
|
|
266
|
+
border_i: style[2]))
|
|
233
267
|
when :csv
|
|
234
268
|
display_message(:data,final_table_rows.map{|t| t.join(CSV_FIELD_SEPARATOR)}.join(CSV_RECORD_SEPARATOR))
|
|
235
269
|
end
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
module Aspera
|
|
3
|
+
module Cli
|
|
4
|
+
# name of command line tool, also used as foldername where config is stored
|
|
5
|
+
PROGRAM_NAME = 'ascli'
|
|
6
|
+
# name of the containing gem, same as in <gem name>.gemspec
|
|
7
|
+
GEM_NAME = 'aspera-cli'
|
|
8
|
+
DOC_URL = "https://www.rubydoc.info/gems/#{GEM_NAME}"
|
|
9
|
+
GEM_URL = "https://rubygems.org/gems/#{GEM_NAME}"
|
|
10
|
+
SRC_URL = 'https://github.com/IBM/aspera-cli'
|
|
11
|
+
# set this to warn in advance when minimum required ruby version will increase
|
|
12
|
+
# for example currently minimum version is 2.4 in gemspec, but future minimum will be 2.5
|
|
13
|
+
# set to currenmt minimum if there is no deprecation
|
|
14
|
+
# the actual current minimum required version is in gemspec at required_ruby_version
|
|
15
|
+
RUBY_FUTURE_MINIMUM_VERSION='2.5'
|
|
16
|
+
end
|
|
17
|
+
end
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
1
2
|
require 'aspera/fasp/listener'
|
|
2
3
|
require 'json'
|
|
3
4
|
|
|
@@ -8,8 +9,8 @@ module Aspera
|
|
|
8
9
|
# FASP event listener display management events as JSON
|
|
9
10
|
class LineDump < Fasp::Listener
|
|
10
11
|
def event_enhanced(data)
|
|
11
|
-
|
|
12
|
-
|
|
12
|
+
$stdout.puts(JSON.generate(data))
|
|
13
|
+
$stdout.flush
|
|
13
14
|
end
|
|
14
15
|
end
|
|
15
16
|
end
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
1
2
|
require 'aspera/fasp/listener'
|
|
2
3
|
require 'aspera/log'
|
|
3
4
|
|
|
@@ -8,7 +9,7 @@ module Aspera
|
|
|
8
9
|
class Logger < Fasp::Listener
|
|
9
10
|
def event_struct(data)
|
|
10
11
|
Log.log.debug(data.to_s)
|
|
11
|
-
Log.log.error(
|
|
12
|
+
Log.log.error((data['Description']).to_s) if data['Type'].eql?('FILEERROR')
|
|
12
13
|
end
|
|
13
14
|
|
|
14
15
|
def event_enhanced(data)
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
1
2
|
require 'aspera/fasp/listener'
|
|
2
3
|
require 'ruby-progressbar'
|
|
3
4
|
|
|
@@ -7,42 +8,39 @@ module Aspera
|
|
|
7
8
|
# a listener to FASP event that displays a progress bar
|
|
8
9
|
class Progress < Fasp::Listener
|
|
9
10
|
def initialize
|
|
11
|
+
super
|
|
10
12
|
@progress=nil
|
|
11
13
|
@cumulative=0
|
|
12
14
|
end
|
|
13
15
|
|
|
14
|
-
BYTE_PER_MEGABIT=1024*1024/8
|
|
16
|
+
BYTE_PER_MEGABIT=(1024*1024)/8
|
|
15
17
|
|
|
16
18
|
def event_struct(data)
|
|
17
19
|
case data['Type']
|
|
18
20
|
when 'NOTIFICATION'
|
|
19
|
-
if data.has_key?('PreTransferBytes')
|
|
21
|
+
if data.has_key?('PreTransferBytes')
|
|
20
22
|
@progress=ProgressBar.create(
|
|
21
|
-
:
|
|
22
|
-
:
|
|
23
|
-
:
|
|
24
|
-
:
|
|
23
|
+
format: '%a %B %p%% %r Mbps %e',
|
|
24
|
+
rate_scale: lambda{|rate|rate/BYTE_PER_MEGABIT},
|
|
25
|
+
title: 'progress',
|
|
26
|
+
total: data['PreTransferBytes'].to_i)
|
|
25
27
|
end
|
|
26
28
|
when 'STOP'
|
|
27
29
|
# stop event when one file is completed
|
|
28
|
-
@cumulative
|
|
30
|
+
@cumulative+=data['Size'].to_i
|
|
29
31
|
when 'STATS'
|
|
30
|
-
if
|
|
31
|
-
if data.has_key?('Bytescont')
|
|
32
|
-
@progress.progress=@cumulative+data['Bytescont'].to_i
|
|
33
|
-
else
|
|
34
|
-
@progress.progress=data['TransferBytes'].to_i
|
|
35
|
-
end
|
|
36
|
-
else
|
|
32
|
+
if @progress.nil?
|
|
37
33
|
puts '.'
|
|
34
|
+
else
|
|
35
|
+
@progress.progress=data.has_key?('Bytescont') ? @cumulative+data['Bytescont'].to_i : data['TransferBytes'].to_i
|
|
38
36
|
end
|
|
39
37
|
when 'DONE'
|
|
40
|
-
if
|
|
41
|
-
@progress.progress=@progress.total
|
|
42
|
-
@progress=nil
|
|
43
|
-
else
|
|
38
|
+
if @progress.nil?
|
|
44
39
|
# terminate progress by going to next line
|
|
45
40
|
puts "\n"
|
|
41
|
+
else
|
|
42
|
+
@progress.progress=@progress.total
|
|
43
|
+
@progress=nil
|
|
46
44
|
end
|
|
47
45
|
end
|
|
48
46
|
end
|
|
@@ -1,5 +1,6 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
1
2
|
require 'aspera/fasp/listener'
|
|
2
|
-
require 'aspera/fasp/
|
|
3
|
+
require 'aspera/fasp/agent_base'
|
|
3
4
|
require 'ruby-progressbar'
|
|
4
5
|
|
|
5
6
|
module Aspera
|
|
@@ -8,6 +9,7 @@ module Aspera
|
|
|
8
9
|
# a listener to FASP event that displays a progress bar
|
|
9
10
|
class ProgressMulti < Fasp::Listener
|
|
10
11
|
def initialize
|
|
12
|
+
super
|
|
11
13
|
@progress_bar=nil
|
|
12
14
|
@sessions={}
|
|
13
15
|
end
|
|
@@ -22,7 +24,7 @@ module Aspera
|
|
|
22
24
|
def update_total
|
|
23
25
|
begin
|
|
24
26
|
@progress_bar.total=@sessions.values.inject(0){|m,s|m+=s[:job_size].to_i;m;}
|
|
25
|
-
rescue
|
|
27
|
+
rescue StandardError
|
|
26
28
|
nil
|
|
27
29
|
end
|
|
28
30
|
end
|
|
@@ -30,7 +32,7 @@ module Aspera
|
|
|
30
32
|
def update_progress
|
|
31
33
|
begin
|
|
32
34
|
@progress_bar.progress=@sessions.values.inject(0){|m,s|m+=s[:current].to_i;m;}
|
|
33
|
-
rescue
|
|
35
|
+
rescue StandardError
|
|
34
36
|
nil
|
|
35
37
|
end
|
|
36
38
|
end
|
|
@@ -38,18 +40,18 @@ module Aspera
|
|
|
38
40
|
def event_enhanced(data)
|
|
39
41
|
if @progress_bar.nil?
|
|
40
42
|
@progress_bar=ProgressBar.create(
|
|
41
|
-
:
|
|
42
|
-
:
|
|
43
|
-
:
|
|
44
|
-
:
|
|
43
|
+
format: '%t %a %B %p%% %r Mbps %e',
|
|
44
|
+
rate_scale: lambda{|rate|rate/BYTE_PER_MEGABIT},
|
|
45
|
+
title: '',
|
|
46
|
+
total: nil)
|
|
45
47
|
end
|
|
46
|
-
if !data.has_key?(Fasp::
|
|
47
|
-
Log.log.error("Internal error: no #{Fasp::
|
|
48
|
+
if !data.has_key?(Fasp::AgentBase::LISTENER_SESSION_ID_S)
|
|
49
|
+
Log.log.error("Internal error: no #{Fasp::AgentBase::LISTENER_SESSION_ID_S} in event: #{data}")
|
|
48
50
|
return
|
|
49
51
|
end
|
|
50
52
|
newtitle=@sessions.length < 2 ? '' : "multi=#{@sessions.length}"
|
|
51
53
|
@progress_bar.title=newtitle unless @progress_bar.title.eql?(newtitle)
|
|
52
|
-
session=@sessions[data[Fasp::
|
|
54
|
+
session=@sessions[data[Fasp::AgentBase::LISTENER_SESSION_ID_S]]||={
|
|
53
55
|
cumulative: 0,
|
|
54
56
|
job_size: 0,
|
|
55
57
|
current: 0
|
|
@@ -58,27 +60,22 @@ module Aspera
|
|
|
58
60
|
when 'INIT' # connection to ascp (get id)
|
|
59
61
|
when 'SESSION' # session information
|
|
60
62
|
when 'NOTIFICATION' # sent from remote
|
|
61
|
-
if data.has_key?('pre_transfer_bytes')
|
|
63
|
+
if data.has_key?('pre_transfer_bytes')
|
|
62
64
|
session[:job_size]=data['pre_transfer_bytes']
|
|
63
65
|
update_total
|
|
64
66
|
end
|
|
65
67
|
when 'STATS' # during transfer
|
|
66
|
-
if
|
|
67
|
-
if data.has_key?('bytescont')
|
|
68
|
-
session[:current]=session[:cumulative]+data['bytescont'].to_i
|
|
69
|
-
update_progress
|
|
70
|
-
else
|
|
71
|
-
session[:current]=data['transfer_bytes'].to_i
|
|
72
|
-
update_progress
|
|
73
|
-
end
|
|
74
|
-
else
|
|
68
|
+
if @progress_bar.total.nil?
|
|
75
69
|
@progress_bar.increment
|
|
70
|
+
else
|
|
71
|
+
session[:current]=data.has_key?('bytescont') ? session[:cumulative]+data['bytescont'].to_i : data['transfer_bytes'].to_i
|
|
72
|
+
update_progress
|
|
76
73
|
end
|
|
77
74
|
when 'STOP'
|
|
78
75
|
# stop event when one file is completed
|
|
79
76
|
session[:cumulative]=session[:cumulative]+data['size'].to_i
|
|
80
77
|
when 'DONE' # end of session
|
|
81
|
-
@sessions.delete(data[Fasp::
|
|
78
|
+
@sessions.delete(data[Fasp::AgentBase::LISTENER_SESSION_ID_S])
|
|
82
79
|
update_progress
|
|
83
80
|
update_total
|
|
84
81
|
else
|