aspera-cli 4.2.1 → 4.5.0
Sign up to get free protection for your applications and to get access to all the features.
- 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
|