aspera-cli 4.2.1 → 4.5.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 +1580 -946
- data/bin/ascli +1 -1
- data/bin/asession +3 -5
- data/docs/Makefile +8 -11
- data/docs/README.erb.md +1521 -829
- data/docs/doc_tools.rb +58 -0
- data/docs/test_env.conf +3 -1
- data/examples/faspex4.rb +28 -19
- data/examples/transfer.rb +2 -2
- data/lib/aspera/aoc.rb +157 -134
- data/lib/aspera/cli/listener/progress_multi.rb +5 -5
- data/lib/aspera/cli/main.rb +106 -48
- data/lib/aspera/cli/manager.rb +19 -20
- data/lib/aspera/cli/plugin.rb +22 -7
- data/lib/aspera/cli/plugins/aoc.rb +260 -208
- data/lib/aspera/cli/plugins/ats.rb +11 -10
- data/lib/aspera/cli/plugins/bss.rb +2 -2
- data/lib/aspera/cli/plugins/config.rb +360 -189
- data/lib/aspera/cli/plugins/faspex.rb +119 -56
- data/lib/aspera/cli/plugins/faspex5.rb +32 -17
- data/lib/aspera/cli/plugins/node.rb +72 -31
- data/lib/aspera/cli/plugins/orchestrator.rb +5 -3
- data/lib/aspera/cli/plugins/preview.rb +94 -68
- data/lib/aspera/cli/plugins/server.rb +16 -5
- data/lib/aspera/cli/plugins/shares.rb +17 -0
- data/lib/aspera/cli/transfer_agent.rb +64 -82
- data/lib/aspera/cli/version.rb +1 -1
- data/lib/aspera/command_line_builder.rb +48 -31
- data/lib/aspera/cos_node.rb +4 -3
- data/lib/aspera/environment.rb +4 -4
- data/lib/aspera/fasp/{manager.rb → agent_base.rb} +7 -6
- data/lib/aspera/fasp/{connect.rb → agent_connect.rb} +46 -39
- data/lib/aspera/fasp/{local.rb → agent_direct.rb} +42 -38
- data/lib/aspera/fasp/{http_gw.rb → agent_httpgw.rb} +50 -29
- data/lib/aspera/fasp/{node.rb → agent_node.rb} +43 -4
- data/lib/aspera/fasp/agent_trsdk.rb +106 -0
- data/lib/aspera/fasp/default.rb +17 -0
- data/lib/aspera/fasp/installation.rb +64 -48
- data/lib/aspera/fasp/parameters.rb +78 -91
- data/lib/aspera/fasp/parameters.yaml +531 -0
- data/lib/aspera/fasp/uri.rb +1 -1
- data/lib/aspera/faspex_gw.rb +12 -11
- data/lib/aspera/id_generator.rb +22 -0
- data/lib/aspera/keychain/encrypted_hash.rb +120 -0
- data/lib/aspera/keychain/macos_security.rb +94 -0
- data/lib/aspera/log.rb +45 -32
- data/lib/aspera/node.rb +9 -4
- data/lib/aspera/oauth.rb +116 -100
- data/lib/aspera/persistency_action_once.rb +11 -7
- data/lib/aspera/persistency_folder.rb +6 -26
- data/lib/aspera/rest.rb +66 -50
- data/lib/aspera/sync.rb +40 -35
- data/lib/aspera/timer_limiter.rb +22 -0
- metadata +86 -29
- data/docs/transfer_spec.html +0 -99
- data/lib/aspera/api_detector.rb +0 -60
- data/lib/aspera/fasp/aoc.rb +0 -24
- data/lib/aspera/secrets.rb +0 -20
@@ -1,19 +1,18 @@
|
|
1
1
|
#!/bin/echo this is a ruby class:
|
2
|
-
require 'aspera/fasp/
|
2
|
+
require 'aspera/fasp/agent_base'
|
3
3
|
require 'aspera/log'
|
4
4
|
require 'aspera/rest'
|
5
5
|
require 'websocket-client-simple'
|
6
6
|
require 'securerandom'
|
7
|
-
require 'openssl'
|
8
7
|
require 'base64'
|
9
8
|
require 'json'
|
10
|
-
require 'uri'
|
11
9
|
|
12
10
|
# ref: https://api.ibm.com/explorer/catalog/aspera/product/ibm-aspera/api/http-gateway-api/doc/guides-toc
|
11
|
+
# https://developer.ibm.com/apis/catalog?search=%22aspera%20http%22
|
13
12
|
module Aspera
|
14
13
|
module Fasp
|
15
|
-
#
|
16
|
-
class
|
14
|
+
# start a transfer using Aspera HTTP Gateway, using web socket session
|
15
|
+
class AgentHttpgw < AgentBase
|
17
16
|
# message returned by HTTP GW in case of success
|
18
17
|
OK_MESSAGE='end upload'
|
19
18
|
# refresh rate for progress
|
@@ -25,20 +24,36 @@ module Aspera
|
|
25
24
|
end
|
26
25
|
|
27
26
|
def upload(transfer_spec)
|
28
|
-
#
|
27
|
+
# total size of all files
|
29
28
|
total_size=0
|
30
|
-
#
|
31
|
-
|
29
|
+
# we need to keep track of actual file path because transfer spec is modified to be sent in web socket
|
30
|
+
source_paths=[]
|
31
|
+
# get source root or nil
|
32
|
+
source_root = (transfer_spec.has_key?('source_root') and !transfer_spec['source_root'].empty?) ? transfer_spec['source_root'] : nil
|
33
|
+
# source root is ignored by GW, used only here
|
34
|
+
transfer_spec.delete('source_root')
|
35
|
+
# compute total size of files to upload (for progress)
|
36
|
+
# modify transfer spec to be suitable for GW
|
32
37
|
transfer_spec['paths'].each do |item|
|
33
|
-
|
34
|
-
item['source']
|
35
|
-
|
36
|
-
|
38
|
+
# save actual file location to be able read contents later
|
39
|
+
full_src_filepath=item['source']
|
40
|
+
# add source root if needed
|
41
|
+
full_src_filepath=File.join(source_root,full_src_filepath) unless source_root.nil?
|
42
|
+
# GW expects a simple file name in 'source' but if user wants to change the name, we take it
|
43
|
+
item['source']=File.basename(item['destination'].nil? ? item['source'] : item['destination'])
|
44
|
+
item['file_size']=File.size(full_src_filepath)
|
45
|
+
total_size+=item['file_size']
|
46
|
+
# save so that we can actually read the file later
|
47
|
+
source_paths.push(full_src_filepath)
|
37
48
|
end
|
49
|
+
|
38
50
|
session_id=SecureRandom.uuid
|
39
51
|
ws=::WebSocket::Client::Simple::Client.new
|
52
|
+
# error message if any in callback
|
40
53
|
error=nil
|
54
|
+
# number of files totally sent
|
41
55
|
received=0
|
56
|
+
# setup callbacks on websocket
|
42
57
|
ws.on :message do |msg|
|
43
58
|
Log.log.info("ws: message: #{msg.data}")
|
44
59
|
message=msg.data
|
@@ -64,44 +79,49 @@ module Aspera
|
|
64
79
|
end
|
65
80
|
# open web socket to end point
|
66
81
|
ws.connect("#{@gw_api.params[:base_url]}/upload")
|
82
|
+
# async wait ready
|
67
83
|
while !ws.open? and error.nil? do
|
68
84
|
Log.log.info("ws: wait")
|
69
85
|
sleep(0.2)
|
70
86
|
end
|
87
|
+
# notify progress bar
|
71
88
|
notify_begin(session_id,total_size)
|
89
|
+
# first step send transfer spec
|
90
|
+
Log.dump(:ws_spec,transfer_spec)
|
72
91
|
ws_send(ws,:transfer_spec,transfer_spec)
|
73
92
|
# current file index
|
74
|
-
|
93
|
+
file_index=0
|
75
94
|
# aggregate size sent
|
76
95
|
sent_bytes=0
|
77
96
|
# last progress event
|
78
|
-
lastevent=
|
97
|
+
lastevent=nil
|
79
98
|
transfer_spec['paths'].each do |item|
|
80
|
-
# TODO: on destination write same path?
|
81
|
-
destination_path=item['source']
|
82
99
|
# TODO: get mime type?
|
83
100
|
file_mime_type=''
|
84
|
-
|
101
|
+
file_size=item['file_size']
|
102
|
+
file_name=File.basename(item[item['destination'].nil? ? 'source' : 'destination'])
|
85
103
|
# compute total number of slices
|
86
|
-
numslices=1+(
|
87
|
-
|
88
|
-
|
89
|
-
|
104
|
+
numslices=1+(file_size-1)/@upload_chunksize
|
105
|
+
File.open(source_paths[file_index]) do |file|
|
106
|
+
# current slice index
|
107
|
+
slicenum=0
|
90
108
|
while !file.eof? do
|
91
109
|
data=file.read(@upload_chunksize)
|
92
110
|
slice_data={
|
93
|
-
name:
|
111
|
+
name: file_name,
|
94
112
|
type: file_mime_type,
|
95
|
-
size:
|
113
|
+
size: file_size,
|
96
114
|
data: Base64.strict_encode64(data),
|
97
115
|
slice: slicenum,
|
98
116
|
total_slices: numslices,
|
99
|
-
fileIndex:
|
117
|
+
fileIndex: file_index
|
100
118
|
}
|
119
|
+
# log without data
|
120
|
+
Log.dump(:slide_data,slice_data.keys.inject({}){|m,i|m[i]=i.eql?(:data)?'base64 data':slice_data[i];m}) if slicenum.eql?(0)
|
101
121
|
ws_send(ws,:slice_upload, slice_data)
|
102
122
|
sent_bytes+=data.length
|
103
123
|
currenttime=Time.now
|
104
|
-
if (currenttime-lastevent)>UPLOAD_REFRESH_SEC
|
124
|
+
if lastevent.nil? or (currenttime-lastevent)>UPLOAD_REFRESH_SEC
|
105
125
|
notify_progress(session_id,sent_bytes)
|
106
126
|
lastevent=currenttime
|
107
127
|
end
|
@@ -109,7 +129,7 @@ module Aspera
|
|
109
129
|
raise error unless error.nil?
|
110
130
|
end
|
111
131
|
end
|
112
|
-
|
132
|
+
file_index+=1
|
113
133
|
end
|
114
134
|
ws.close
|
115
135
|
notify_end(session_id)
|
@@ -150,7 +170,8 @@ module Aspera
|
|
150
170
|
raise "GW URL must be set" unless !@gw_api.nil?
|
151
171
|
raise "option: must be hash (or nil)" unless options.is_a?(Hash)
|
152
172
|
raise "paths: must be Array" unless transfer_spec['paths'].is_a?(Array)
|
153
|
-
raise "
|
173
|
+
raise "only token based transfer is supported in GW" unless transfer_spec['token'].is_a?(String)
|
174
|
+
Log.dump(:user_spec,transfer_spec)
|
154
175
|
transfer_spec['authentication']||='token'
|
155
176
|
case transfer_spec['direction']
|
156
177
|
when 'send'
|
@@ -158,7 +179,7 @@ module Aspera
|
|
158
179
|
when 'receive'
|
159
180
|
download(transfer_spec)
|
160
181
|
else
|
161
|
-
raise "
|
182
|
+
raise "unexpected direction: [#{transfer_spec['direction']}]"
|
162
183
|
end
|
163
184
|
end # start_transfer
|
164
185
|
|
@@ -188,6 +209,6 @@ module Aspera
|
|
188
209
|
@upload_chunksize=128000 # TODO: configurable ?
|
189
210
|
end
|
190
211
|
|
191
|
-
end #
|
212
|
+
end # AgentHttpgw
|
192
213
|
end
|
193
214
|
end
|
@@ -1,4 +1,4 @@
|
|
1
|
-
require 'aspera/fasp/
|
1
|
+
require 'aspera/fasp/agent_base'
|
2
2
|
require 'aspera/log'
|
3
3
|
require 'tty-spinner'
|
4
4
|
|
@@ -6,10 +6,30 @@ module Aspera
|
|
6
6
|
module Fasp
|
7
7
|
# this singleton class is used by the CLI to provide a common interface to start a transfer
|
8
8
|
# before using it, the use must set the `node_api` member.
|
9
|
-
class
|
10
|
-
|
9
|
+
class AgentNode < AgentBase
|
10
|
+
# option include: root_id if the node is an access key
|
11
|
+
attr_writer :options
|
12
|
+
def initialize(options)
|
13
|
+
raise "node specification must be Hash" unless options.is_a?(Hash)
|
14
|
+
[:url,:username,:password].each { |k| raise "missing parameter [#{k}] in node specification: #{options}" unless options.has_key?(k) }
|
11
15
|
super()
|
12
|
-
|
16
|
+
# root id is required for access key
|
17
|
+
@root_id=options[:root_id]
|
18
|
+
rest_params={ base_url: options[:url]}
|
19
|
+
if options[:password].match(/^Bearer /)
|
20
|
+
rest_params[:headers]={
|
21
|
+
'X-Aspera-AccessKey'=>options[:username],
|
22
|
+
'Authorization' =>options[:password]
|
23
|
+
}
|
24
|
+
raise "root_id is required for access key" if @root_id.nil?
|
25
|
+
else
|
26
|
+
rest_params[:auth]={
|
27
|
+
type: :basic,
|
28
|
+
username: options[:username],
|
29
|
+
password: options[:password]
|
30
|
+
}
|
31
|
+
end
|
32
|
+
@node_api=Rest.new(rest_params)
|
13
33
|
# TODO: currently only supports one transfer. This is bad shortcut. but ok for CLI.
|
14
34
|
@transfer_id=nil
|
15
35
|
end
|
@@ -32,6 +52,25 @@ module Aspera
|
|
32
52
|
|
33
53
|
# generic method
|
34
54
|
def start_transfer(transfer_spec,options=nil)
|
55
|
+
# add root id if access key
|
56
|
+
if ! @root_id.nil?
|
57
|
+
case transfer_spec['direction']
|
58
|
+
when 'send';transfer_spec['source_root_id']=@root_id
|
59
|
+
when 'receive';transfer_spec['destination_root_id']=@root_id
|
60
|
+
else raise "unexpected direction in ts: #{transfer_spec['direction']}"
|
61
|
+
end
|
62
|
+
end
|
63
|
+
# manage special additional parameter
|
64
|
+
if transfer_spec.has_key?('EX_ssh_key_paths') and transfer_spec['EX_ssh_key_paths'].is_a?(Array) and !transfer_spec['EX_ssh_key_paths'].empty?
|
65
|
+
# not standard, so place standard field
|
66
|
+
if transfer_spec.has_key?('ssh_private_key')
|
67
|
+
Log.log.warn('Both ssh_private_key and EX_ssh_key_paths are present, using ssh_private_key')
|
68
|
+
else
|
69
|
+
Log.log.warn('EX_ssh_key_paths has multiple keys, using first one only') unless transfer_spec['EX_ssh_key_paths'].length.eql?(1)
|
70
|
+
transfer_spec['ssh_private_key']=File.read(transfer_spec['EX_ssh_key_paths'].first)
|
71
|
+
transfer_spec.delete('EX_ssh_key_paths')
|
72
|
+
end
|
73
|
+
end
|
35
74
|
if transfer_spec['tags'].is_a?(Hash) and transfer_spec['tags']['aspera'].is_a?(Hash)
|
36
75
|
transfer_spec['tags']['aspera']['xfer_retry']||=150
|
37
76
|
end
|
@@ -0,0 +1,106 @@
|
|
1
|
+
require 'aspera/fasp/agent_base'
|
2
|
+
require 'aspera/fasp/installation'
|
3
|
+
require 'json'
|
4
|
+
|
5
|
+
module Aspera
|
6
|
+
module Fasp
|
7
|
+
class AgentTrsdk < AgentBase
|
8
|
+
DEFAULT_OPTIONS = {
|
9
|
+
address: '127.0.0.1',
|
10
|
+
port: 55002,
|
11
|
+
}
|
12
|
+
private_constant :DEFAULT_OPTIONS
|
13
|
+
|
14
|
+
# options come from transfer_info
|
15
|
+
def initialize(user_opts)
|
16
|
+
raise "expecting Hash (or nil), but have #{user_opts.class}" unless user_opts.nil? or user_opts.is_a?(Hash)
|
17
|
+
# set default options and override if specified
|
18
|
+
options=DEFAULT_OPTIONS.clone
|
19
|
+
if !user_opts.nil?
|
20
|
+
user_opts.each do |k,v|
|
21
|
+
if DEFAULT_OPTIONS.has_key?(k)
|
22
|
+
options[k]=v
|
23
|
+
else
|
24
|
+
raise "Unknown local agent parameter: #{k}, expect one of #{DEFAULT_OPTIONS.keys.map{|i|i.to_s}.join(",")}"
|
25
|
+
end
|
26
|
+
end
|
27
|
+
end
|
28
|
+
Log.log.debug("options= #{options}")
|
29
|
+
super()
|
30
|
+
# load and create SDK stub
|
31
|
+
$LOAD_PATH.unshift(Installation.instance.sdk_ruby_folder)
|
32
|
+
require 'transfer_services_pb'
|
33
|
+
@transfer_client = Transfersdk::TransferService::Stub.new("#{options[:address]}:#{options[:port]}",:this_channel_is_insecure)
|
34
|
+
begin
|
35
|
+
get_info_response = @transfer_client.get_info(Transfersdk::InstanceInfoRequest.new)
|
36
|
+
Log.log.debug("daemon info: #{get_info_response}")
|
37
|
+
rescue GRPC::Unavailable => e
|
38
|
+
Log.log.warn("no daemon present, starting daemon...")
|
39
|
+
# location of daemon binary
|
40
|
+
bin_folder=File.realpath(File.join(Installation.instance.sdk_ruby_folder,'..'))
|
41
|
+
# config file and logs are created in same folder
|
42
|
+
conf_file = File.join(bin_folder,'sdk.conf')
|
43
|
+
log_base = File.join(bin_folder,'transferd')
|
44
|
+
# create a config file for daemon
|
45
|
+
config = {
|
46
|
+
address: options[:address],
|
47
|
+
port: options[:port],
|
48
|
+
fasp_runtime: {
|
49
|
+
use_embedded: false,
|
50
|
+
user_defined: {
|
51
|
+
bin: bin_folder,
|
52
|
+
etc: bin_folder,
|
53
|
+
}
|
54
|
+
}
|
55
|
+
}
|
56
|
+
File.write(conf_file,config.to_json)
|
57
|
+
trd_pid = Process.spawn(Installation.instance.path(:transferd),'--config' , conf_file, out: "#{log_base}.out", err: "#{log_base}.err")
|
58
|
+
Process.detach(trd_pid)
|
59
|
+
sleep(2.0)
|
60
|
+
retry
|
61
|
+
end
|
62
|
+
end
|
63
|
+
|
64
|
+
def start_transfer(transfer_spec,options=nil)
|
65
|
+
# create a transfer request
|
66
|
+
transfer_request = Transfersdk::TransferRequest.new(
|
67
|
+
transferType: Transfersdk::TransferType::FILE_REGULAR, # transfer type (file/stream)
|
68
|
+
config: Transfersdk::TransferConfig.new, # transfer configuration
|
69
|
+
transferSpec: transfer_spec.to_json) # transfer definition
|
70
|
+
# send start transfer request to the transfer manager daemon
|
71
|
+
start_transfer_response = @transfer_client.start_transfer(transfer_request)
|
72
|
+
Log.log.debug("start transfer response #{start_transfer_response}")
|
73
|
+
@transfer_id = start_transfer_response.transferId
|
74
|
+
Log.log.debug("transfer started with id #{@transfer_id}")
|
75
|
+
end
|
76
|
+
|
77
|
+
def wait_for_transfers_completion
|
78
|
+
started=false
|
79
|
+
# monitor transfer status
|
80
|
+
@transfer_client.monitor_transfers(Transfersdk::RegistrationRequest.new(transferId: [@transfer_id])) do |response|
|
81
|
+
Log.dump(:response, response.to_h)
|
82
|
+
#Log.log.debug("#{response.sessionInfo.preTransferBytes} #{response.transferInfo.bytesTransferred}")
|
83
|
+
case response.status
|
84
|
+
when :RUNNING
|
85
|
+
if !started and !response.sessionInfo.preTransferBytes.eql?(0)
|
86
|
+
notify_begin(@transfer_id,response.sessionInfo.preTransferBytes)
|
87
|
+
started=true
|
88
|
+
elsif started
|
89
|
+
notify_progress(@transfer_id,response.transferInfo.bytesTransferred)
|
90
|
+
end
|
91
|
+
when :FAILED, :COMPLETED, :CANCELED
|
92
|
+
notify_end(@transfer_id)
|
93
|
+
raise Fasp::Error.new(JSON.parse(response.message)['Description']) unless :COMPLETED.eql?(response.status)
|
94
|
+
break
|
95
|
+
when :QUEUED,:UNKNOWN_STATUS,:PAUSED,:ORPHANED
|
96
|
+
# ignore
|
97
|
+
else
|
98
|
+
Log.log.error("unknown status#{response.status}")
|
99
|
+
end
|
100
|
+
end
|
101
|
+
# TODO return status
|
102
|
+
return []
|
103
|
+
end
|
104
|
+
end
|
105
|
+
end
|
106
|
+
end
|
@@ -0,0 +1,17 @@
|
|
1
|
+
module Aspera
|
2
|
+
module Fasp
|
3
|
+
# default parameters
|
4
|
+
class Default
|
5
|
+
# (public) default transfer username for access key based transfers
|
6
|
+
ACCESS_KEY_TRANSFER_USER='xfer'
|
7
|
+
SSH_PORT=33001
|
8
|
+
UDP_PORT=33001
|
9
|
+
AK_TSPEC_BASE={
|
10
|
+
'remote_user' => ACCESS_KEY_TRANSFER_USER,
|
11
|
+
'ssh_port' => SSH_PORT,
|
12
|
+
'fasp_port' => UDP_PORT
|
13
|
+
}
|
14
|
+
end
|
15
|
+
end
|
16
|
+
end
|
17
|
+
|
@@ -10,7 +10,7 @@ require 'fileutils'
|
|
10
10
|
module Aspera
|
11
11
|
module Fasp
|
12
12
|
# Singleton that tells where to find ascp and other local resources (keys..) , using the "path(symb)" method.
|
13
|
-
# It is used by object :
|
13
|
+
# It is used by object : AgentDirect to find necessary resources
|
14
14
|
# By default it takes the first Aspera product found specified in product_locations
|
15
15
|
# but the user can specify ascp location by calling:
|
16
16
|
# Installation.instance.use_ascp_from_product(product_name)
|
@@ -22,6 +22,9 @@ module Aspera
|
|
22
22
|
PRODUCT_CLI_V1='Aspera CLI'
|
23
23
|
PRODUCT_DRIVE='Aspera Drive'
|
24
24
|
PRODUCT_ENTSRV='Enterprise Server'
|
25
|
+
# protobuf generated files from sdk
|
26
|
+
EXT_RUBY_PROTOBUF='_pb.rb'
|
27
|
+
RB_SDK_FOLDER='lib'
|
25
28
|
MAX_REDIRECT_SDK=2
|
26
29
|
private_constant :MAX_REDIRECT_SDK
|
27
30
|
# set ascp executable path
|
@@ -29,9 +32,10 @@ module Aspera
|
|
29
32
|
@path_to_ascp=v
|
30
33
|
end
|
31
34
|
|
32
|
-
|
33
|
-
|
34
|
-
|
35
|
+
def sdk_ruby_folder
|
36
|
+
ruby_pb_folder=File.join(folder_path,RB_SDK_FOLDER)
|
37
|
+
FileUtils.mkdir_p(ruby_pb_folder) unless Dir.exist?(ruby_pb_folder)
|
38
|
+
return ruby_pb_folder
|
35
39
|
end
|
36
40
|
|
37
41
|
# location of SDK files
|
@@ -100,6 +104,8 @@ module Aspera
|
|
100
104
|
file=@path_to_ascp
|
101
105
|
# note that there might be a .exe at the end
|
102
106
|
file=file.gsub('ascp','ascp4') if k.eql?(:ascp4)
|
107
|
+
when :transferd
|
108
|
+
file=transferd_filepath
|
103
109
|
when :ssh_bypass_key_dsa
|
104
110
|
file=File.join(folder_path,'aspera_bypass_dsa.pem')
|
105
111
|
File.write(file,get_key('dsa',1)) unless File.exist?(file)
|
@@ -182,16 +188,22 @@ module Aspera
|
|
182
188
|
return [:ssh_bypass_key_dsa,:ssh_bypass_key_rsa].map{|i|Installation.instance.path(i)}
|
183
189
|
end
|
184
190
|
|
191
|
+
# use in plugin `config`
|
192
|
+
def get_ascp_version(exe_path)
|
193
|
+
return get_exe_version(exe_path,'-A')
|
194
|
+
end
|
195
|
+
|
185
196
|
# Check that specified path is ascp and get version
|
186
|
-
def
|
187
|
-
raise "
|
188
|
-
|
189
|
-
|
190
|
-
cmd_out=%x{"#{
|
197
|
+
def get_exe_version(exe_path,vers_arg)
|
198
|
+
raise "ERROR: nil arg" if exe_path.nil?
|
199
|
+
return nil unless File.exist?(exe_path)
|
200
|
+
exe_version=nil
|
201
|
+
cmd_out=%x{"#{exe_path}" #{vers_arg}}
|
191
202
|
raise "An error occured when testing #{ascp_filename}: #{cmd_out}" unless $? == 0
|
192
203
|
# get version from ascp, only after full extract, as windows requires DLLs (SSL/TLS/etc...)
|
193
|
-
m=cmd_out.match(/
|
194
|
-
|
204
|
+
m=cmd_out.match(/ version ([0-9\.]+)/)
|
205
|
+
exe_version=m[1] unless m.nil?
|
206
|
+
return exe_version
|
195
207
|
end
|
196
208
|
|
197
209
|
# download aspera SDK or use local file
|
@@ -205,54 +217,49 @@ module Aspera
|
|
205
217
|
raise 'use format: file:///<path>' unless sdk_url.start_with?('file:///')
|
206
218
|
sdk_zip_path=sdk_url.gsub(%r{^file:///},'')
|
207
219
|
else
|
208
|
-
|
209
|
-
begin
|
210
|
-
Aspera::Rest.new(base_url: sdk_url).call(operation: 'GET',save_to_file: sdk_zip_path)
|
211
|
-
rescue Aspera::RestCallError => e
|
212
|
-
if e.response.is_a?(Net::HTTPRedirection)
|
213
|
-
if redirect_remain > 0
|
214
|
-
redirect_remain-=1
|
215
|
-
sdk_url=e.response['location']
|
216
|
-
retry
|
217
|
-
else
|
218
|
-
raise "Too many redirect"
|
219
|
-
end
|
220
|
-
else
|
221
|
-
raise e
|
222
|
-
end
|
223
|
-
end
|
220
|
+
Aspera::Rest.new(base_url: sdk_url, redirect_max: 3).call(operation: 'GET',save_to_file: sdk_zip_path)
|
224
221
|
end
|
225
|
-
# SDK is organized by architecture
|
226
|
-
filter="/#{Environment.architecture}/"
|
227
|
-
ascp_path=nil
|
228
|
-
sdk_path=folder_path
|
229
222
|
# rename old install
|
230
|
-
if
|
231
|
-
Log.log.warn("Previous install exists, renaming.")
|
232
|
-
File.rename(
|
223
|
+
if ! Dir.empty?(folder_path)
|
224
|
+
Log.log.warn("Previous install exists, renaming folder.")
|
225
|
+
File.rename(folder_path,"#{folder_path}.#{Time.now.strftime("%Y%m%d%H%M%S")}")
|
226
|
+
# TODO: delete old archives ?
|
233
227
|
end
|
234
|
-
#
|
235
|
-
|
236
|
-
|
228
|
+
# SDK is organized by architecture
|
229
|
+
arch_filter="#{Environment.architecture}/"
|
230
|
+
# extract files from archive
|
237
231
|
Zip::File.open(sdk_zip_path) do |zip_file|
|
238
232
|
zip_file.each do |entry|
|
239
|
-
#
|
240
|
-
if entry.name.
|
241
|
-
|
242
|
-
|
233
|
+
# skip folder entries
|
234
|
+
next if entry.name.end_with?('/')
|
235
|
+
dest_folder=nil
|
236
|
+
# binaries
|
237
|
+
dest_folder=folder_path if entry.name.include?(arch_filter)
|
238
|
+
# ruby adapters
|
239
|
+
dest_folder=sdk_ruby_folder if entry.name.end_with?(EXT_RUBY_PROTOBUF)
|
240
|
+
if !dest_folder.nil?
|
241
|
+
File.open(File.join(dest_folder,File.basename(entry.name)), 'wb') do |output_stream|
|
243
242
|
IO.copy_stream(entry.get_input_stream, output_stream)
|
244
243
|
end
|
245
|
-
if File.basename(entry.name).eql?(ascp_filename)
|
246
|
-
FileUtils.chmod(0755,archive_file)
|
247
|
-
ascp_path=archive_file
|
248
|
-
end
|
249
244
|
end
|
250
245
|
end
|
251
246
|
end
|
252
247
|
File.unlink(sdk_zip_path) rescue nil # Windows may give error
|
253
|
-
|
254
|
-
|
255
|
-
|
248
|
+
# ensure license file are generated so that ascp invokation for version works
|
249
|
+
self.path(:aspera_license)
|
250
|
+
self.path(:aspera_conf)
|
251
|
+
ascp_path=File.join(folder_path,ascp_filename)
|
252
|
+
raise "No #{ascp_filename} found in SDK archive" unless File.exist?(ascp_path)
|
253
|
+
FileUtils.chmod(0755,ascp_path)
|
254
|
+
FileUtils.chmod(0755,ascp_path.gsub('ascp','ascp4'))
|
255
|
+
ascp_version=get_ascp_version(File.join(folder_path,ascp_filename))
|
256
|
+
trd_path=transferd_filepath
|
257
|
+
Log.log.warn("No #{trd_path} in SDK archive") unless File.exist?(trd_path)
|
258
|
+
FileUtils.chmod(0755,trd_path) if File.exist?(trd_path)
|
259
|
+
transferd_version=get_exe_version(trd_path,'version')
|
260
|
+
sdk_version = transferd_version||ascp_version
|
261
|
+
File.write(File.join(folder_path,PRODUCT_INFO),"<product><name>IBM Aspera SDK</name><version>#{sdk_version}</version></product>")
|
262
|
+
return sdk_version
|
256
263
|
end
|
257
264
|
|
258
265
|
private
|
@@ -288,6 +295,15 @@ module Aspera
|
|
288
295
|
@sdk_folder
|
289
296
|
end
|
290
297
|
|
298
|
+
# filename for ascp with optional extension (Windows)
|
299
|
+
def ascp_filename
|
300
|
+
return 'ascp'+Environment.exe_extension
|
301
|
+
end
|
302
|
+
|
303
|
+
def transferd_filepath
|
304
|
+
return File.join(folder_path,'asperatransferd'+Environment.exe_extension)
|
305
|
+
end
|
306
|
+
|
291
307
|
# @return product folders depending on OS fields
|
292
308
|
# :expected M app name is taken from the manifest if present, else defaults to this value
|
293
309
|
# :app_root M main folder for the application
|