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
@@ -1,4 +1,6 @@
|
|
1
|
-
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'aspera/fasp/transfer_spec'
|
2
4
|
require 'aspera/cli/listener/logger'
|
3
5
|
require 'aspera/cli/listener/progress_multi'
|
4
6
|
|
@@ -9,42 +11,42 @@ module Aspera
|
|
9
11
|
# provides CLI options to select one of the transfer agents (FASP/ascp client)
|
10
12
|
class TransferAgent
|
11
13
|
# special value for --sources : read file list from arguments
|
12
|
-
FILE_LIST_FROM_ARGS='@args'
|
14
|
+
FILE_LIST_FROM_ARGS = '@args'
|
13
15
|
# special value for --sources : read file list from transfer spec (--ts)
|
14
|
-
FILE_LIST_FROM_TRANSFER_SPEC='@ts'
|
15
|
-
DEFAULT_TRANSFER_NOTIF_TMPL
|
16
|
-
From: <%=from_name%> <<%=from_email%>>
|
17
|
-
To: <<%=to%>>
|
18
|
-
Subject: <%=subject%>
|
16
|
+
FILE_LIST_FROM_TRANSFER_SPEC = '@ts'
|
17
|
+
DEFAULT_TRANSFER_NOTIF_TMPL = <<~END_OF_TEMPLATE
|
18
|
+
From: <%=from_name%> <<%=from_email%>>
|
19
|
+
To: <<%=to%>>
|
20
|
+
Subject: <%=subject%>
|
19
21
|
|
20
|
-
Transfer is: <%=global_transfer_status%>
|
22
|
+
Transfer is: <%=global_transfer_status%>
|
21
23
|
|
22
|
-
<%=ts.to_yaml%>
|
23
|
-
END_OF_TEMPLATE
|
24
|
+
<%=ts.to_yaml%>
|
25
|
+
END_OF_TEMPLATE
|
24
26
|
#% (formating bug in eclipse)
|
25
27
|
private_constant :FILE_LIST_FROM_ARGS,:FILE_LIST_FROM_TRANSFER_SPEC,:DEFAULT_TRANSFER_NOTIF_TMPL
|
26
|
-
TRANSFER_AGENTS=[
|
28
|
+
TRANSFER_AGENTS = %i[direct node connect httpgw trsdk].freeze
|
27
29
|
|
28
30
|
# @param env external objects: option manager, config file manager
|
29
31
|
def initialize(opt_mgr,config)
|
30
|
-
@opt_mgr=opt_mgr
|
31
|
-
@config=config
|
32
|
+
@opt_mgr = opt_mgr
|
33
|
+
@config = config
|
32
34
|
# command line can override transfer spec
|
33
|
-
@transfer_spec_cmdline={'create_dir'=>true}
|
35
|
+
@transfer_spec_cmdline = {'create_dir' => true}
|
34
36
|
# the currently selected transfer agent
|
35
|
-
@agent=nil
|
36
|
-
@progress_listener=Listener::ProgressMulti.new
|
37
|
+
@agent = nil
|
38
|
+
@progress_listener = Listener::ProgressMulti.new
|
37
39
|
# source/destination pair, like "paths" of transfer spec
|
38
|
-
@transfer_paths=nil
|
40
|
+
@transfer_paths = nil
|
39
41
|
@opt_mgr.set_obj_attr(:ts,self,:option_transfer_spec)
|
40
|
-
@opt_mgr.add_opt_simple(:ts,"override transfer spec values (Hash, use @json: prefix), current=#{@opt_mgr.get_option(:ts
|
41
|
-
@opt_mgr.add_opt_simple(:local_resume,"set resume policy (Hash, use @json: prefix), current=#{@opt_mgr.get_option(:local_resume
|
42
|
-
@opt_mgr.add_opt_simple(:to_folder,
|
43
|
-
@opt_mgr.add_opt_simple(:sources,
|
44
|
-
@opt_mgr.add_opt_simple(:transfer_info,
|
45
|
-
@opt_mgr.add_opt_list(:src_type
|
46
|
-
@opt_mgr.add_opt_list(:transfer,TRANSFER_AGENTS,
|
47
|
-
@opt_mgr.add_opt_list(:progress
|
42
|
+
@opt_mgr.add_opt_simple(:ts,"override transfer spec values (Hash, use @json: prefix), current=#{@opt_mgr.get_option(:ts)}")
|
43
|
+
@opt_mgr.add_opt_simple(:local_resume,"set resume policy (Hash, use @json: prefix), current=#{@opt_mgr.get_option(:local_resume)}")
|
44
|
+
@opt_mgr.add_opt_simple(:to_folder,'destination folder for downloaded files')
|
45
|
+
@opt_mgr.add_opt_simple(:sources,'list of source files (see doc)')
|
46
|
+
@opt_mgr.add_opt_simple(:transfer_info,'parameters for transfer agent')
|
47
|
+
@opt_mgr.add_opt_list(:src_type,%i[list pair],'type of file list')
|
48
|
+
@opt_mgr.add_opt_list(:transfer,TRANSFER_AGENTS,'type of transfer agent')
|
49
|
+
@opt_mgr.add_opt_list(:progress,%i[none native multi],'type of progress bar')
|
48
50
|
@opt_mgr.set_option(:transfer,:direct)
|
49
51
|
@opt_mgr.set_option(:src_type,:list)
|
50
52
|
@opt_mgr.set_option(:progress,:native) # use native ascp progress bar as it is more reliable
|
@@ -58,12 +60,12 @@ END_OF_TEMPLATE
|
|
58
60
|
|
59
61
|
def option_transfer_spec_deep_merge(ts); @transfer_spec_cmdline.deep_merge!(ts); end
|
60
62
|
|
61
|
-
def
|
62
|
-
@agent=instance
|
63
|
+
def agent_instance=(instance)
|
64
|
+
@agent = instance
|
63
65
|
@agent.add_listener(Listener::Logger.new)
|
64
66
|
# use local progress bar if asked so, or if native and non local ascp (because only local ascp has native progress bar)
|
65
|
-
if @opt_mgr.get_option(:progress
|
66
|
-
(@opt_mgr.get_option(:progress
|
67
|
+
if @opt_mgr.get_option(:progress,is_type: :mandatory).eql?(:multi) ||
|
68
|
+
(@opt_mgr.get_option(:progress,is_type: :mandatory).eql?(:native) && !instance.class.to_s.eql?('Aspera::Fasp::AgentDirect'))
|
67
69
|
@agent.add_listener(@progress_listener)
|
68
70
|
end
|
69
71
|
end
|
@@ -71,25 +73,27 @@ END_OF_TEMPLATE
|
|
71
73
|
# analyze options and create new agent if not already created or set
|
72
74
|
def set_agent_by_options
|
73
75
|
return nil unless @agent.nil?
|
74
|
-
agent_type
|
76
|
+
agent_type = @opt_mgr.get_option(:transfer,is_type: :mandatory)
|
77
|
+
# agent plugin is loaded on demand to avoid loading unnecessary dependencies
|
75
78
|
require "aspera/fasp/agent_#{agent_type}"
|
76
|
-
agent_options
|
77
|
-
raise CliBadArgument,"the transfer agent configuration shall be Hash, not #{agent_options.class} (#{agent_options}),
|
79
|
+
agent_options = @opt_mgr.get_option(:transfer_info)
|
80
|
+
raise CliBadArgument,"the transfer agent configuration shall be Hash, not #{agent_options.class} (#{agent_options}), "\
|
81
|
+
'use either @json:<json> or @preset:<parameter set name>' unless [Hash,NilClass].include?(agent_options.class)
|
78
82
|
# special case
|
79
|
-
if agent_type.eql?(:node)
|
80
|
-
param_set_name
|
81
|
-
raise CliBadArgument,"No default node configured, Please specify --#{:transfer_info.to_s.
|
82
|
-
agent_options
|
83
|
+
if agent_type.eql?(:node) && agent_options.nil?
|
84
|
+
param_set_name = @config.get_plugin_default_config_name(:node)
|
85
|
+
raise CliBadArgument,"No default node configured, Please specify --#{:transfer_info.to_s.tr('_','-')}" if param_set_name.nil?
|
86
|
+
agent_options = @config.preset_by_name(param_set_name)
|
83
87
|
end
|
84
88
|
# special case
|
85
|
-
if agent_type.eql?(:direct)
|
86
|
-
agent_options={} if agent_options.nil?
|
87
|
-
agent_options[:quiet]=false
|
89
|
+
if agent_type.eql?(:direct) && @opt_mgr.get_option(:progress,is_type: :mandatory).eql?(:native)
|
90
|
+
agent_options = {} if agent_options.nil?
|
91
|
+
agent_options[:quiet] = false
|
88
92
|
end
|
89
|
-
agent_options=agent_options.symbolize_keys if agent_options.is_a?(Hash)
|
93
|
+
agent_options = agent_options.symbolize_keys if agent_options.is_a?(Hash)
|
90
94
|
# get agent instance
|
91
|
-
new_agent=Kernel.const_get("Aspera::Fasp::Agent#{agent_type.capitalize}").new(agent_options)
|
92
|
-
|
95
|
+
new_agent = Kernel.const_get("Aspera::Fasp::Agent#{agent_type.capitalize}").new(agent_options)
|
96
|
+
self.agent_instance = new_agent
|
93
97
|
return nil
|
94
98
|
end
|
95
99
|
|
@@ -97,14 +101,14 @@ END_OF_TEMPLATE
|
|
97
101
|
# sets default if needed
|
98
102
|
# param: 'send' or 'receive'
|
99
103
|
def destination_folder(direction)
|
100
|
-
dest_folder
|
104
|
+
dest_folder = @opt_mgr.get_option(:to_folder)
|
101
105
|
return File.expand_path(dest_folder) unless dest_folder.nil?
|
102
|
-
dest_folder
|
106
|
+
dest_folder = @transfer_spec_cmdline['destination_root']
|
103
107
|
return dest_folder unless dest_folder.nil?
|
104
108
|
# default: / on remote, . on local
|
105
109
|
case direction.to_s
|
106
|
-
when
|
107
|
-
when
|
110
|
+
when Fasp::TransferSpec::DIRECTION_SEND then dest_folder = '/'
|
111
|
+
when Fasp::TransferSpec::DIRECTION_RECEIVE then dest_folder = '.'
|
108
112
|
else raise "wrong direction: #{direction}"
|
109
113
|
end
|
110
114
|
return dest_folder
|
@@ -112,45 +116,46 @@ END_OF_TEMPLATE
|
|
112
116
|
|
113
117
|
# This is how the list of files to be transfered is specified
|
114
118
|
# get paths suitable for transfer spec from command line
|
115
|
-
# @return {:
|
119
|
+
# @return {source: (mandatory), destination: (optional)}
|
116
120
|
# computation is done only once, cache is kept in @transfer_paths
|
117
121
|
def ts_source_paths
|
118
122
|
# return cache if set
|
119
123
|
return @transfer_paths unless @transfer_paths.nil?
|
120
124
|
# start with lower priority : get paths from transfer spec on command line
|
121
|
-
@transfer_paths
|
125
|
+
@transfer_paths = @transfer_spec_cmdline['paths'] if @transfer_spec_cmdline.has_key?('paths')
|
122
126
|
# is there a source list option ?
|
123
|
-
file_list
|
127
|
+
file_list = @opt_mgr.get_option(:sources)
|
124
128
|
case file_list
|
125
129
|
when nil,FILE_LIST_FROM_ARGS
|
126
|
-
Log.log.debug(
|
130
|
+
Log.log.debug('getting file list as parameters')
|
127
131
|
# get remaining arguments
|
128
|
-
file_list
|
129
|
-
raise CliBadArgument,
|
132
|
+
file_list = @opt_mgr.get_next_argument('source file list',expected: :multiple)
|
133
|
+
raise CliBadArgument,'specify at least one file on command line or use '\
|
134
|
+
"--sources=#{FILE_LIST_FROM_TRANSFER_SPEC} to use transfer spec" if !file_list.is_a?(Array) || file_list.empty?
|
130
135
|
when FILE_LIST_FROM_TRANSFER_SPEC
|
131
|
-
Log.log.debug(
|
132
|
-
special_case_direct_with_list
|
133
|
-
raise CliBadArgument,
|
136
|
+
Log.log.debug('assume list provided in transfer spec')
|
137
|
+
(special_case_direct_with_list = @opt_mgr.get_option(:transfer,is_type: :mandatory).eql?(:direct)) && Fasp::Parameters.ts_has_file_list(@transfer_spec_cmdline)
|
138
|
+
raise CliBadArgument,'transfer spec on command line must have sources' if @transfer_paths.nil? && !special_case_direct_with_list
|
134
139
|
# here we assume check of sources is made in transfer agent
|
135
140
|
return @transfer_paths
|
136
141
|
when Array
|
137
|
-
Log.log.debug(
|
138
|
-
raise CliBadArgument,
|
142
|
+
Log.log.debug('getting file list as extended value')
|
143
|
+
raise CliBadArgument,'sources must be a Array of String' if !file_list.reject{|f|f.is_a?(String)}.empty?
|
139
144
|
else
|
140
145
|
raise CliBadArgument,"sources must be a Array, not #{file_list.class}"
|
141
146
|
end
|
142
147
|
# here, file_list is an Array or String
|
143
148
|
if !@transfer_paths.nil?
|
144
|
-
Log.log.warn(
|
149
|
+
Log.log.warn('--sources overrides paths from --ts')
|
145
150
|
end
|
146
|
-
case @opt_mgr.get_option(:src_type
|
151
|
+
case @opt_mgr.get_option(:src_type,is_type: :mandatory)
|
147
152
|
when :list
|
148
153
|
# when providing a list, just specify source
|
149
|
-
@transfer_paths=file_list.map{|i|{'source'=>i}}
|
154
|
+
@transfer_paths = file_list.map{|i|{'source' => i}}
|
150
155
|
when :pair
|
151
156
|
raise CliBadArgument,"When using pair, provide an even number of paths: #{file_list.length}" unless file_list.length.even?
|
152
|
-
@transfer_paths=file_list.each_slice(2).to_a.map{|s,d|{'source'=>s,'destination'=>d}}
|
153
|
-
else raise
|
157
|
+
@transfer_paths = file_list.each_slice(2).to_a.map{|s,d|{'source' => s,'destination' => d}}
|
158
|
+
else raise 'Unsupported src_type'
|
154
159
|
end
|
155
160
|
Log.log.debug("paths=#{@transfer_paths}")
|
156
161
|
return @transfer_paths
|
@@ -163,18 +168,18 @@ END_OF_TEMPLATE
|
|
163
168
|
# other options are carried to specific agent
|
164
169
|
def start(transfer_spec,tr_opts)
|
165
170
|
# check parameters
|
166
|
-
raise
|
167
|
-
raise
|
171
|
+
raise 'transfer_spec must be hash' unless transfer_spec.is_a?(Hash)
|
172
|
+
raise 'tr_opts must be hash' unless tr_opts.is_a?(Hash)
|
168
173
|
# process :src option
|
169
174
|
case transfer_spec['direction']
|
170
|
-
when
|
175
|
+
when Fasp::TransferSpec::DIRECTION_RECEIVE
|
171
176
|
# init default if required in any case
|
172
|
-
@transfer_spec_cmdline['destination_root']||=destination_folder(transfer_spec['direction'])
|
173
|
-
when
|
177
|
+
@transfer_spec_cmdline['destination_root'] ||= destination_folder(transfer_spec['direction'])
|
178
|
+
when Fasp::TransferSpec::DIRECTION_SEND
|
174
179
|
case tr_opts[:src]
|
175
180
|
when :direct
|
176
181
|
# init default if required
|
177
|
-
@transfer_spec_cmdline['destination_root']||=destination_folder(transfer_spec['direction'])
|
182
|
+
@transfer_spec_cmdline['destination_root'] ||= destination_folder(transfer_spec['direction'])
|
178
183
|
when :node_gen3
|
179
184
|
# in that case, destination is set in return by application (API/upload_setup)
|
180
185
|
# but to_folder was used in initial API call
|
@@ -190,14 +195,15 @@ END_OF_TEMPLATE
|
|
190
195
|
tr_opts.delete(:src)
|
191
196
|
|
192
197
|
# update command line paths, unless destination already has one
|
193
|
-
@transfer_spec_cmdline['paths']=transfer_spec['paths'] || ts_source_paths
|
198
|
+
@transfer_spec_cmdline['paths'] = transfer_spec['paths'] || ts_source_paths
|
194
199
|
|
195
200
|
transfer_spec.merge!(@transfer_spec_cmdline)
|
196
201
|
# create transfer agent
|
197
|
-
|
202
|
+
set_agent_by_options
|
198
203
|
Log.log.debug("transfer agent is a #{@agent.class}")
|
199
204
|
@agent.start_transfer(transfer_spec,tr_opts)
|
200
|
-
|
205
|
+
# list of : :success or error message
|
206
|
+
result = @agent.wait_for_transfers_completion
|
201
207
|
@progress_listener.reset
|
202
208
|
Fasp::AgentBase.validate_status_list(result)
|
203
209
|
send_email_transfer_notification(transfer_spec,result)
|
@@ -205,13 +211,13 @@ END_OF_TEMPLATE
|
|
205
211
|
end
|
206
212
|
|
207
213
|
def send_email_transfer_notification(transfer_spec,statuses)
|
208
|
-
return if @opt_mgr.get_option(:notif_to
|
209
|
-
global_status=self.class.session_status(statuses)
|
210
|
-
email_vars={
|
214
|
+
return if @opt_mgr.get_option(:notif_to).nil?
|
215
|
+
global_status = self.class.session_status(statuses)
|
216
|
+
email_vars = {
|
211
217
|
global_transfer_status: global_status,
|
212
|
-
subject:
|
213
|
-
body:
|
214
|
-
ts:
|
218
|
+
subject: "ascli transfer: #{global_status}",
|
219
|
+
body: "Transfer is: #{global_status}",
|
220
|
+
ts: transfer_spec
|
215
221
|
}
|
216
222
|
@config.send_email_template(email_vars,DEFAULT_TRANSFER_NOTIF_TMPL)
|
217
223
|
end
|
@@ -219,7 +225,7 @@ END_OF_TEMPLATE
|
|
219
225
|
# @return :success if all sessions statuses returned by "start" are success
|
220
226
|
# else return the first error exception object
|
221
227
|
def self.session_status(statuses)
|
222
|
-
error_statuses=statuses.
|
228
|
+
error_statuses = statuses.reject{|i|i.eql?(:success)}
|
223
229
|
return :success if error_statuses.empty?
|
224
230
|
return error_statuses.first
|
225
231
|
end
|
@@ -228,7 +234,6 @@ END_OF_TEMPLATE
|
|
228
234
|
def shutdown
|
229
235
|
@agent.shutdown if @agent.respond_to?(:shutdown)
|
230
236
|
end
|
231
|
-
|
232
237
|
end
|
233
238
|
end
|
234
239
|
end
|
data/lib/aspera/cli/version.rb
CHANGED
data/lib/aspera/colors.rb
CHANGED
@@ -1,43 +1,52 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
# simple vt100 colors
|
2
4
|
class String
|
3
|
-
|
4
|
-
|
5
|
+
class << self
|
6
|
+
private
|
7
|
+
|
8
|
+
def vtcmd(code);"\e[#{code}m";end
|
9
|
+
end
|
5
10
|
# see https://en.wikipedia.org/wiki/ANSI_escape_code
|
6
11
|
# symbol is the method name added to String
|
7
12
|
# it adds control chars to set color (and reset at the end).
|
8
13
|
VTSTYLES = {
|
9
|
-
:
|
10
|
-
:
|
11
|
-
:
|
12
|
-
:
|
13
|
-
:
|
14
|
-
:
|
15
|
-
:
|
16
|
-
:
|
17
|
-
:
|
18
|
-
:
|
19
|
-
:
|
20
|
-
:
|
21
|
-
:
|
22
|
-
:
|
23
|
-
:
|
24
|
-
:
|
25
|
-
:
|
26
|
-
:
|
27
|
-
:
|
28
|
-
:
|
29
|
-
:
|
30
|
-
}
|
14
|
+
bold: 1,
|
15
|
+
italic: 3,
|
16
|
+
underline: 4,
|
17
|
+
blink: 5,
|
18
|
+
reverse_color: 7,
|
19
|
+
black: 30,
|
20
|
+
red: 31,
|
21
|
+
green: 32,
|
22
|
+
brown: 33,
|
23
|
+
blue: 34,
|
24
|
+
magenta: 35,
|
25
|
+
cyan: 36,
|
26
|
+
gray: 37,
|
27
|
+
bg_black: 40,
|
28
|
+
bg_red: 41,
|
29
|
+
bg_green: 42,
|
30
|
+
bg_brown: 43,
|
31
|
+
bg_blue: 44,
|
32
|
+
bg_magenta: 45,
|
33
|
+
bg_cyan: 46,
|
34
|
+
bg_gray: 47
|
35
|
+
}.freeze
|
31
36
|
private_constant :VTSTYLES
|
32
37
|
# defines methods to String, one per entry in VTSTYLES
|
33
38
|
VTSTYLES.each do |name,code|
|
34
|
-
|
35
|
-
|
36
|
-
|
39
|
+
if $stderr.tty?
|
40
|
+
begin_seq = vtcmd(code)
|
41
|
+
end_code = 0 # by default reset all
|
42
|
+
if code <= 7 then 20 + code
|
43
|
+
elsif code <= 37 then 39
|
44
|
+
elsif code <= 47 then 49
|
45
|
+
end
|
46
|
+
end_seq = vtcmd(end_code)
|
37
47
|
define_method(name){"#{begin_seq}#{self}#{end_seq}"}
|
38
48
|
else
|
39
49
|
define_method(name){self}
|
40
50
|
end
|
41
|
-
public name
|
42
51
|
end
|
43
52
|
end
|
@@ -1,42 +1,49 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
module Aspera
|
2
4
|
# helper class to build command line from a parameter list (key-value hash)
|
3
5
|
# constructor takes hash: { 'param1':'value1', ...}
|
4
6
|
# process_param is called repeatedly with all known parameters
|
5
7
|
# add_env_args is called to get resulting param list and env var (also checks that all params were used)
|
6
8
|
class CommandLineBuilder
|
7
|
-
#
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
|
9
|
+
# parameter with onne of those tags is an ascp command line option with --
|
10
|
+
CLTYPE_OPTIONS=%i[opt_without_arg opt_with_arg].freeze
|
11
|
+
class<<self
|
12
|
+
# transform yes/no to true/false
|
13
|
+
def yes_to_true(value)
|
14
|
+
case value
|
15
|
+
when 'yes' then return true
|
16
|
+
when 'no' then return false
|
17
|
+
end
|
18
|
+
raise "unsupported value: #{value}"
|
12
19
|
end
|
13
|
-
raise "unsupported value: #{value}"
|
14
|
-
end
|
15
20
|
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
options
|
21
|
+
# Called by provider of definition before constructor of this class so that params_definition has all mandatory fields
|
22
|
+
def normalize_description(d)
|
23
|
+
d.each do |param_name,options|
|
24
|
+
raise "Expecting Hash, but have #{options.class} in #{param_name}" unless options.is_a?(Hash)
|
25
|
+
#options[:accepted_types]=:bool if options[:cltype].eql?(:envvar) and !options.has_key?(:accepted_types)
|
26
|
+
# by default : not mandatory
|
27
|
+
options[:mandatory] ||= false
|
28
|
+
options[:desc] ||= ''
|
29
|
+
# by default : string, unless it's without arg
|
30
|
+
if !options.has_key?(:accepted_types)
|
31
|
+
options[:accepted_types] = options[:cltype].eql?(:opt_without_arg) ? :bool : :string
|
32
|
+
end
|
33
|
+
# single type is placed in array
|
34
|
+
options[:accepted_types] = [options[:accepted_types]] unless options[:accepted_types].is_a?(Array)
|
35
|
+
# add default switch name if not present
|
36
|
+
if !options.has_key?(:clswitch) && options.has_key?(:cltype) && CLTYPE_OPTIONS.include?(options[:cltype])
|
37
|
+
options[:clswitch] = '--' + param_name.to_s.tr('_','-')
|
38
|
+
end
|
32
39
|
end
|
33
40
|
end
|
34
|
-
|
41
|
+
end
|
35
42
|
|
36
43
|
private
|
37
44
|
|
38
45
|
# clvarname : command line variable name
|
39
|
-
def env_name(
|
46
|
+
def env_name(_param_name,options)
|
40
47
|
return options[:clvarname]
|
41
48
|
end
|
42
49
|
|
@@ -46,11 +53,11 @@ module Aspera
|
|
46
53
|
|
47
54
|
# @param param_hash
|
48
55
|
def initialize(param_hash,params_definition)
|
49
|
-
@param_hash=param_hash
|
50
|
-
@params_definition=params_definition
|
51
|
-
@result_env={}
|
52
|
-
@result_args=[]
|
53
|
-
@used_param_names=[]
|
56
|
+
@param_hash = param_hash # keep reference so that it can be modified by caller before calling `process_params`
|
57
|
+
@params_definition = params_definition
|
58
|
+
@result_env = {}
|
59
|
+
@result_args = []
|
60
|
+
@used_param_names = []
|
54
61
|
end
|
55
62
|
|
56
63
|
def warn_unrecognized_params
|
@@ -85,43 +92,55 @@ module Aspera
|
|
85
92
|
# @param action : type of processing: ignore getvalue envvar opt_without_arg opt_with_arg defer
|
86
93
|
# @param options : options for type
|
87
94
|
def process_param(param_name,action=nil)
|
88
|
-
options
|
89
|
-
action=options[:cltype] if action.nil?
|
95
|
+
options = @params_definition[param_name]
|
90
96
|
# should not happen
|
91
|
-
|
97
|
+
if options.nil?
|
98
|
+
Log.log.warn("Unknown parameter #{param_name}")
|
99
|
+
return
|
100
|
+
end
|
101
|
+
action = options[:cltype] if action.nil?
|
92
102
|
# check mandatory parameter (nil is valid value)
|
93
|
-
raise Fasp::Error
|
94
|
-
parameter_value
|
103
|
+
raise Fasp::Error, "Missing mandatory parameter: #{param_name}" if options[:mandatory] && !@param_hash.has_key?(param_name)
|
104
|
+
parameter_value = @param_hash[param_name]
|
105
|
+
|
95
106
|
#parameter_value=options[:default] if parameter_value.nil? and options.has_key?(:default)
|
96
|
-
|
107
|
+
|
108
|
+
# Check parameter type
|
109
|
+
expected_classes = options[:accepted_types].map do |s|
|
97
110
|
case s
|
98
|
-
when :string
|
99
|
-
when :array
|
100
|
-
when :hash
|
101
|
-
when :int
|
102
|
-
when :bool
|
111
|
+
when :string then String
|
112
|
+
when :array then Array
|
113
|
+
when :hash then Hash
|
114
|
+
when :int then Integer
|
115
|
+
when :bool then [TrueClass,FalseClass]
|
103
116
|
else raise "INTERNAL: unexpected value: #{s}"
|
104
117
|
end
|
105
118
|
end.flatten
|
106
|
-
#
|
107
|
-
|
119
|
+
raise Fasp::Error,"#{param_name} is : #{parameter_value.class} (#{parameter_value}), shall be #{options[:accepted_types]}, " \
|
120
|
+
unless parameter_value.nil? || expected_classes.include?(parameter_value.class)
|
108
121
|
@used_param_names.push(param_name) unless action.eql?(:defer)
|
109
122
|
|
110
123
|
# process only non-nil values
|
111
124
|
return nil if parameter_value.nil?
|
112
125
|
|
113
|
-
|
126
|
+
# check that value is of an accepted type (string, int bool)
|
127
|
+
raise "Value #{parameter_value} is not allowed for #{param_name}" if options.has_key?(:enum) && !options[:enum].include?(parameter_value)
|
128
|
+
|
129
|
+
# convert some values if value on command line needs processing from value in structure
|
130
|
+
case options[:clconvert]
|
131
|
+
when Hash
|
114
132
|
# translate using conversion table
|
115
|
-
new_value=options[:
|
116
|
-
raise "unsupported value: #{parameter_value}" if new_value.nil?
|
117
|
-
parameter_value=new_value
|
118
|
-
|
119
|
-
|
120
|
-
|
121
|
-
|
122
|
-
|
123
|
-
|
124
|
-
|
133
|
+
new_value = options[:clconvert][parameter_value]
|
134
|
+
raise "unsupported value: #{parameter_value}, expect: #{options[:clconvert].keys.join(', ')}" if new_value.nil?
|
135
|
+
parameter_value = new_value
|
136
|
+
when String
|
137
|
+
# :clconvert has name of class and encoding method
|
138
|
+
convclass,convmethod = options[:clconvert].split('.')
|
139
|
+
newvalue = Kernel.const_get(convclass).send(convmethod,parameter_value)
|
140
|
+
raise Fasp::Error, "unsupported #{param_name}: #{parameter_value}" if newvalue.nil?
|
141
|
+
parameter_value = newvalue
|
142
|
+
when NilClass
|
143
|
+
else raise "not expected type for clconvert #{options[:clconvert].class} for #{param_name}"
|
125
144
|
end
|
126
145
|
|
127
146
|
case action
|
@@ -133,21 +152,23 @@ module Aspera
|
|
133
152
|
# define ascp parameter in env var from transfer spec
|
134
153
|
@result_env[env_name(param_name,options)] = parameter_value
|
135
154
|
when :opt_without_arg # if present and true : just add option without value
|
136
|
-
add_param=false
|
155
|
+
add_param = false
|
137
156
|
case parameter_value
|
138
|
-
when false# nothing to put on command line, no creation by default
|
139
|
-
when true
|
140
|
-
else raise Fasp::Error
|
157
|
+
when false then nil # nothing to put on command line, no creation by default
|
158
|
+
when true then add_param = true
|
159
|
+
else raise Fasp::Error, "unsupported #{param_name}: #{parameter_value}"
|
141
160
|
end
|
142
|
-
add_param
|
143
|
-
add_command_line_options([options[:
|
161
|
+
add_param = !add_param if options[:add_on_false]
|
162
|
+
add_command_line_options([options[:clswitch]]) if add_param
|
144
163
|
when :opt_with_arg # transform into command line option with value
|
145
164
|
#parameter_value=parameter_value.to_s if parameter_value.is_a?(Integer)
|
146
|
-
parameter_value=[parameter_value] unless parameter_value.is_a?(Array)
|
165
|
+
parameter_value = [parameter_value] unless parameter_value.is_a?(Array)
|
147
166
|
# if transfer_spec value is an array, applies option many times
|
148
|
-
parameter_value.each{|v|add_command_line_options([options[:
|
167
|
+
parameter_value.each{|v|add_command_line_options([options[:clswitch],v])}
|
168
|
+
when NilClass
|
169
|
+
Log.log.debug("Ignoring parameter: #{param_name}")
|
149
170
|
else
|
150
|
-
raise "
|
171
|
+
raise "ERROR: unknown action: #{action}/#{action.class}"
|
151
172
|
end
|
152
173
|
end
|
153
174
|
end
|