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