aspera-cli 4.0.0 → 4.2.2
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/README.md +843 -304
- data/bin/dascli +13 -0
- data/docs/Makefile +4 -4
- data/docs/README.erb.md +805 -172
- data/docs/test_env.conf +22 -3
- data/examples/aoc.rb +14 -3
- data/examples/faspex4.rb +89 -0
- data/lib/aspera/aoc.rb +87 -108
- data/lib/aspera/cli/formater.rb +2 -0
- data/lib/aspera/cli/main.rb +89 -49
- data/lib/aspera/cli/plugin.rb +9 -4
- data/lib/aspera/cli/plugins/alee.rb +1 -1
- data/lib/aspera/cli/plugins/aoc.rb +188 -173
- data/lib/aspera/cli/plugins/ats.rb +2 -2
- data/lib/aspera/cli/plugins/config.rb +218 -145
- data/lib/aspera/cli/plugins/console.rb +2 -2
- data/lib/aspera/cli/plugins/faspex.rb +114 -61
- data/lib/aspera/cli/plugins/faspex5.rb +85 -43
- data/lib/aspera/cli/plugins/node.rb +3 -3
- data/lib/aspera/cli/plugins/preview.rb +59 -45
- data/lib/aspera/cli/plugins/server.rb +23 -8
- data/lib/aspera/cli/transfer_agent.rb +77 -49
- data/lib/aspera/cli/version.rb +1 -1
- data/lib/aspera/command_line_builder.rb +49 -31
- data/lib/aspera/cos_node.rb +33 -28
- data/lib/aspera/environment.rb +2 -2
- data/lib/aspera/fasp/connect.rb +28 -21
- data/lib/aspera/fasp/http_gw.rb +140 -28
- data/lib/aspera/fasp/installation.rb +93 -46
- data/lib/aspera/fasp/local.rb +88 -45
- data/lib/aspera/fasp/manager.rb +15 -0
- data/lib/aspera/fasp/node.rb +4 -4
- data/lib/aspera/fasp/parameters.rb +59 -101
- data/lib/aspera/fasp/parameters.yaml +531 -0
- data/lib/aspera/fasp/resume_policy.rb +13 -12
- data/lib/aspera/fasp/uri.rb +1 -1
- data/lib/aspera/log.rb +1 -1
- data/lib/aspera/node.rb +61 -1
- data/lib/aspera/oauth.rb +49 -46
- data/lib/aspera/persistency_folder.rb +9 -4
- data/lib/aspera/preview/file_types.rb +53 -21
- data/lib/aspera/preview/generator.rb +3 -3
- data/lib/aspera/rest.rb +29 -18
- data/lib/aspera/secrets.rb +20 -0
- data/lib/aspera/sync.rb +40 -35
- data/lib/aspera/temp_file_manager.rb +19 -0
- data/lib/aspera/web_auth.rb +105 -0
- metadata +54 -20
- data/docs/transfer_spec.html +0 -99
data/docs/test_env.conf
CHANGED
@@ -6,7 +6,7 @@ default:
|
|
6
6
|
aoc: tst_aoc1
|
7
7
|
faspex: tst_faspex
|
8
8
|
faspex5: tst_faspex5
|
9
|
-
shares:
|
9
|
+
shares: tst_shares_1
|
10
10
|
shares2: tst_shares2
|
11
11
|
node: tst_node
|
12
12
|
server: tst_server
|
@@ -19,7 +19,6 @@ default:
|
|
19
19
|
cli_default:
|
20
20
|
interactive: your value here
|
21
21
|
smtp: your value here
|
22
|
-
ascp_path: your value here
|
23
22
|
local_user:
|
24
23
|
ssh_keys: your value here
|
25
24
|
smtp_config:
|
@@ -48,8 +47,23 @@ tst_node_faspex:
|
|
48
47
|
url: your value here
|
49
48
|
username: your value here
|
50
49
|
password: your value here
|
50
|
+
tst_faspex5_boot:
|
51
|
+
url: your value here
|
52
|
+
auth: your value here
|
53
|
+
username: your value here
|
54
|
+
password: your value here
|
55
|
+
tst_faspex5_web:
|
56
|
+
url: your value here
|
57
|
+
auth: your value here
|
58
|
+
redirect_uri: your value here
|
59
|
+
client_id: your value here
|
60
|
+
client_secret: your value here
|
51
61
|
tst_faspex5:
|
52
62
|
url: your value here
|
63
|
+
auth: your value here
|
64
|
+
client_id: your value here
|
65
|
+
client_secret: your value here
|
66
|
+
private_key: your value here
|
53
67
|
username: your value here
|
54
68
|
password: your value here
|
55
69
|
tst_shares:
|
@@ -94,6 +108,7 @@ tst_ak_preview:
|
|
94
108
|
url: your value here
|
95
109
|
username: your value here
|
96
110
|
password: your value here
|
111
|
+
mimemagic: your value here
|
97
112
|
tst_node_preview:
|
98
113
|
url: your value here
|
99
114
|
username: your value here
|
@@ -110,6 +125,8 @@ misc:
|
|
110
125
|
faspex_publink_send_to_fxuser: your value here
|
111
126
|
faspex_publink_send_to_dropbox: your value here
|
112
127
|
shares_upload: your value here
|
128
|
+
console_smart_id: your value here
|
129
|
+
console_smart_file: your value here
|
113
130
|
orch_workflow_id: your value here
|
114
131
|
file_dcm: your value here
|
115
132
|
file_pdf: your value here
|
@@ -122,6 +139,7 @@ misc:
|
|
122
139
|
aoc_publink_recv_from_aocuser: your value here
|
123
140
|
aoc_publink_send_shd_inbox: your value here
|
124
141
|
aoc_publink_send_aoc_user: your value here
|
142
|
+
aoc_publink_send_use_pass: your value here
|
125
143
|
aoc_publink_folder: your value here
|
126
144
|
aoc_shbx_ws: your value here
|
127
145
|
aoc_shbx_name: your value here
|
@@ -137,4 +155,5 @@ misc:
|
|
137
155
|
email_internal: your value here
|
138
156
|
email_external: your value here
|
139
157
|
aoc_org: your value here
|
140
|
-
|
158
|
+
aoc_user_email: your value here
|
159
|
+
http_gw_fqdn_port: your value here
|
data/examples/aoc.rb
CHANGED
@@ -4,11 +4,22 @@ require 'aspera/log'
|
|
4
4
|
|
5
5
|
Aspera::Log.instance.level=:debug
|
6
6
|
|
7
|
+
if ! ARGV.length.eql?(3)
|
8
|
+
Aspera::Log.log.error("wrong number of args: #{ARGV.length}")
|
9
|
+
Aspera::Log.log.error("Usage: #{$0} <aoc URL> <aoc username> <aoc private key content>")
|
10
|
+
Aspera::Log.log.error("Example: #{$0} https://myorg.ibmaspera.com john@example.com $(cat /home/john/my_key.pem)")
|
11
|
+
Process.exit(1)
|
12
|
+
end
|
13
|
+
|
14
|
+
aoc_url=ARGV[0]
|
15
|
+
aoc_user=ARGV[1]
|
16
|
+
aoc_key_value=ARGV[2]
|
17
|
+
|
7
18
|
aocapi=Aspera::AoC.new(
|
8
|
-
url:
|
19
|
+
url: aoc_url,
|
9
20
|
auth: :jwt,
|
10
|
-
private_key:
|
11
|
-
username:
|
21
|
+
private_key: aoc_key_value,
|
22
|
+
username: aoc_user,
|
12
23
|
scope: 'user:all',
|
13
24
|
subpath: 'api/v1')
|
14
25
|
|
data/examples/faspex4.rb
ADDED
@@ -0,0 +1,89 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
# find Faspex API here: https://developer.ibm.com/apis/catalog/?search=faspex
|
3
|
+
# this example makes use of class Aspera::Rest for REST calls, alternatively class RestClient of gem rest-client could be used
|
4
|
+
# this example makes use of class Aspera::Fasp::Local for transfers, alternatively the official "Transfer SDK" could be used
|
5
|
+
# Aspera SDK can be downloaded with: `ascli conf ascp install` , it installs in $HOME/.aspera/ascli/sdk
|
6
|
+
require 'aspera/rest'
|
7
|
+
require 'aspera/log'
|
8
|
+
require 'aspera/fasp/local'
|
9
|
+
|
10
|
+
tmpdir=ENV['tmp']||Dir.tmpdir || '.'
|
11
|
+
|
12
|
+
# Set high log level for the example, decrease to :warn usually
|
13
|
+
Aspera::Log.instance.level=:debug
|
14
|
+
|
15
|
+
# Set folder where SDK is installed (mandatory)
|
16
|
+
# (if ascp is not there, the lib will try to find in usual locations)
|
17
|
+
# (if data files are not there, they will be created)
|
18
|
+
Aspera::Fasp::Installation.instance.folder = tmpdir
|
19
|
+
|
20
|
+
if ! ARGV.length.eql?(3)
|
21
|
+
Aspera::Log.log.error("Wrong number of args: #{ARGV.length}")
|
22
|
+
Aspera::Log.log.error("Usage: #{$0} <faspex URL> <faspex username> <faspex password>")
|
23
|
+
Aspera::Log.log.error("Example: #{$0} https://faspex.com/aspera/faspex john p@sSw0rd")
|
24
|
+
Process.exit(1)
|
25
|
+
end
|
26
|
+
|
27
|
+
faspex_url=ARGV[0] # typically: https://faspex.example.com/aspera/faspex
|
28
|
+
faspex_user=ARGV[1]
|
29
|
+
faspex_pass=ARGV[2]
|
30
|
+
|
31
|
+
# comment out this if certificate is valid, keep line to ignore certificate
|
32
|
+
Aspera::Rest.insecure=true
|
33
|
+
|
34
|
+
# 1: Faspex 4 API v3
|
35
|
+
#---------------
|
36
|
+
|
37
|
+
# create REST API object
|
38
|
+
api_v3=Aspera::Rest.new({
|
39
|
+
:base_url => faspex_url,
|
40
|
+
:auth => {
|
41
|
+
:type => :basic,
|
42
|
+
:username => faspex_user,
|
43
|
+
:password => faspex_pass
|
44
|
+
}})
|
45
|
+
|
46
|
+
# very simple api call
|
47
|
+
api_v3.read('me')
|
48
|
+
|
49
|
+
# 2: send a package
|
50
|
+
#---------------
|
51
|
+
|
52
|
+
# create a sample file to send
|
53
|
+
file_to_send=File.join(tmpdir,'myfile.bin')
|
54
|
+
File.open(file_to_send, "w") {|f| f.write("sample data") }
|
55
|
+
# package creation parameters
|
56
|
+
package_create_params={'delivery'=>{'title'=>'test package','recipients'=>['aspera.user1@gmail.com'],'sources'=>[{'paths'=>[file_to_send]}]}}
|
57
|
+
pkg_created=api_v3.create('send',package_create_params)[:data]
|
58
|
+
# get transfer specification (normally: only one)
|
59
|
+
transfer_spec=pkg_created['xfer_sessions'].first
|
60
|
+
# set paths of files to send
|
61
|
+
transfer_spec['paths']=[{'source'=>file_to_send}]
|
62
|
+
# get the local agent (i.e. ascp)
|
63
|
+
transfer_client=Aspera::Fasp::Local.new
|
64
|
+
# disable ascp output on stdout (optional)
|
65
|
+
transfer_client.quiet=true
|
66
|
+
# start transfer (asynchronous)
|
67
|
+
job_id=transfer_client.start_transfer(transfer_spec)
|
68
|
+
# wait for all transfer completion (for the example)
|
69
|
+
result=transfer_client.wait_for_transfers_completion
|
70
|
+
# notify of any transfer error
|
71
|
+
result.select{|i|!i.eql?(:success)}.each do |e|
|
72
|
+
Aspera::Log.log.error("A transfer error occured: #{e.message}")
|
73
|
+
end
|
74
|
+
|
75
|
+
# 3: Faspex 4 API v4
|
76
|
+
#---------------
|
77
|
+
api_v4=Aspera::Rest.new({
|
78
|
+
:base_url => faspex_url+'/api',
|
79
|
+
:auth => {
|
80
|
+
:type => :oauth2,
|
81
|
+
:base_url => faspex_url+'/auth/oauth2',
|
82
|
+
:grant => :header_userpass,
|
83
|
+
:user_name => faspex_user,
|
84
|
+
:user_pass => faspex_pass,
|
85
|
+
:scope => 'admin'
|
86
|
+
}})
|
87
|
+
|
88
|
+
# Use it. Note that Faspex 4 API v4 is totally different from Faspex 4 v3 APIs, see ref on line 2
|
89
|
+
Aspera::Log.dump('users',api_v4.read('users')[:data])
|
data/lib/aspera/aoc.rb
CHANGED
@@ -9,6 +9,8 @@ module Aspera
|
|
9
9
|
private
|
10
10
|
@@use_standard_ports = true
|
11
11
|
|
12
|
+
API_V1='api/v1'
|
13
|
+
|
12
14
|
PRODUCT_NAME='Aspera on Cloud'
|
13
15
|
# Production domain of AoC
|
14
16
|
PROD_DOMAIN='ibmaspera.com'
|
@@ -42,11 +44,6 @@ module Aspera
|
|
42
44
|
FILES_APP='files'
|
43
45
|
PACKAGES_APP='packages'
|
44
46
|
|
45
|
-
CLIENT_RANDOM={
|
46
|
-
'aspera.global-cli-client' => 'frpmsRsG4mjZ0PlxCgdJlvONqBg4Vlpz_IX7gXmBMAfsgMLy2FO6CXLodKfKAuhqnCqSptLbe_wdmnm9JRuEPO-PpFqpq_Kb',
|
47
|
-
'aspera.drive' => 'UegzQ3LcbLht5dLYAXaR-7ZMnJ6-kwPEXWEXaqLSOMGmtzNA9r6kPFLElqBfq66BfgMabdO96k5sPXV-H8M3vsx9LbGlewF1'
|
48
|
-
}
|
49
|
-
|
50
47
|
def self.get_client_info(client_name=CLIENT_APPS.first)
|
51
48
|
client_index=CLIENT_APPS.index(client_name)
|
52
49
|
raise "no such pre-defined client: #{client_name}" if client_index.nil?
|
@@ -68,9 +65,14 @@ module Aspera
|
|
68
65
|
return organization,instance_domain
|
69
66
|
end
|
70
67
|
|
68
|
+
# base API url depends on domain, which could be "qa.xxx"
|
69
|
+
def self.api_base_url(api_domain=PROD_DOMAIN)
|
70
|
+
return "https://api.#{api_domain}"
|
71
|
+
end
|
72
|
+
|
71
73
|
def self.metering_api(entitlement_id,customer_id,api_domain=PROD_DOMAIN)
|
72
74
|
return Rest.new({
|
73
|
-
:base_url => "
|
75
|
+
:base_url => "#{api_base_url(api_domain)}/metering/v1",
|
74
76
|
:headers => {'X-Aspera-Entitlement-Authorization' => Rest.basic_creds(entitlement_id,customer_id)}
|
75
77
|
})
|
76
78
|
end
|
@@ -121,12 +123,12 @@ module Aspera
|
|
121
123
|
raise RuntimeError,'too many redirections'
|
122
124
|
end
|
123
125
|
|
124
|
-
# @param :link,:url,:auth,:client_id,:client_secret,:scope,:redirect_uri,:private_key,:username,:subpath
|
126
|
+
# @param :link,:url,:auth,:client_id,:client_secret,:scope,:redirect_uri,:private_key,:username,:subpath,:password (for pub link)
|
125
127
|
def initialize(opt)
|
126
128
|
# access key secrets are provided out of band to get node api access
|
127
129
|
# key: access key
|
128
130
|
# value: associated secret
|
129
|
-
@
|
131
|
+
@key_chain=nil
|
130
132
|
|
131
133
|
# init rest params
|
132
134
|
aoc_rest_p={:auth=>{:type =>:oauth2}}
|
@@ -147,12 +149,12 @@ module Aspera
|
|
147
149
|
|
148
150
|
# get org name and domain from url
|
149
151
|
organization,instance_domain=self.class.parse_url(opt[:url])
|
150
|
-
# this is the base API url
|
151
|
-
api_base_url
|
152
|
-
#
|
153
|
-
aoc_rest_p[:base_url]="#{
|
152
|
+
# this is the base API url
|
153
|
+
api_url_base=self.class.api_base_url(instance_domain)
|
154
|
+
# API URL, including subpath (version ...)
|
155
|
+
aoc_rest_p[:base_url]="#{api_url_base}/#{opt[:subpath]}"
|
154
156
|
# base auth URL
|
155
|
-
aoc_auth_p[:base_url] = "#{
|
157
|
+
aoc_auth_p[:base_url] = "#{api_url_base}/#{OAUTH_API_SUBPATH}/#{organization}"
|
156
158
|
aoc_auth_p[:client_id]=opt[:client_id]
|
157
159
|
aoc_auth_p[:client_secret] = opt[:client_secret]
|
158
160
|
|
@@ -185,23 +187,19 @@ module Aspera
|
|
185
187
|
aoc_auth_p[:jwt_subject] = opt[:username]
|
186
188
|
aoc_auth_p[:jwt_private_key_obj] = OpenSSL::PKey::RSA.new(private_key_PEM_string)
|
187
189
|
when :url_token
|
190
|
+
aoc_auth_p[:password]=opt[:password] unless opt[:password].nil?
|
188
191
|
# nothing more
|
189
192
|
else raise "ERROR: unsupported auth method: #{aoc_auth_p[:grant]}"
|
190
193
|
end
|
191
194
|
super(aoc_rest_p)
|
192
195
|
end
|
193
196
|
|
194
|
-
def
|
195
|
-
@
|
196
|
-
|
197
|
+
def key_chain=(keychain)
|
198
|
+
raise "keychain already set" unless @key_chain.nil?
|
199
|
+
@key_chain=keychain
|
197
200
|
nil
|
198
201
|
end
|
199
202
|
|
200
|
-
def has_secret(ak)
|
201
|
-
Log.log.debug("has key:#{ak} -> #{@secrets.has_key?(ak)}")
|
202
|
-
return @secrets.has_key?(ak)
|
203
|
-
end
|
204
|
-
|
205
203
|
# additional transfer spec (tags) for package information
|
206
204
|
def self.package_tags(package_info,operation)
|
207
205
|
return {'tags'=>{'aspera'=>{'files'=>{
|
@@ -293,13 +291,14 @@ module Aspera
|
|
293
291
|
# no scope: requires secret
|
294
292
|
# if secret provided beforehand: use it
|
295
293
|
def get_node_api(node_info,node_scope=nil)
|
294
|
+
# X-Aspera-AccessKey required for bearer token only
|
296
295
|
node_rest_params={
|
297
296
|
:base_url => node_info['url'],
|
298
297
|
:headers => {'X-Aspera-AccessKey'=>node_info['access_key']},
|
299
298
|
}
|
300
|
-
ak_secret=@
|
299
|
+
ak_secret=@key_chain.get_secret(node_info['access_key'],false)
|
301
300
|
if ak_secret.nil? and node_scope.nil?
|
302
|
-
raise
|
301
|
+
raise "There must be at least one of: 'secret' or 'scope' for access key #{node_info['access_key']}"
|
303
302
|
end
|
304
303
|
# if secret provided on command line or if there is no scope
|
305
304
|
if !ak_secret.nil? or node_scope.nil?
|
@@ -312,7 +311,7 @@ module Aspera
|
|
312
311
|
node_rest_params[:auth]=self.params[:auth].clone
|
313
312
|
node_rest_params[:auth][:scope]=self.class.node_scope(node_info['access_key'],node_scope)
|
314
313
|
end
|
315
|
-
return
|
314
|
+
return Node.new(node_rest_params)
|
316
315
|
end
|
317
316
|
|
318
317
|
# check that parameter has necessary types
|
@@ -328,102 +327,82 @@ module Aspera
|
|
328
327
|
return node_info,file_id
|
329
328
|
end
|
330
329
|
|
331
|
-
#
|
332
|
-
def
|
333
|
-
|
334
|
-
|
330
|
+
# add entry to list if test block is success
|
331
|
+
def process_find_files(entry,path)
|
332
|
+
begin
|
333
|
+
# add to result if match filter
|
334
|
+
@find_state[:found].push(entry.merge({'path'=>path})) if @find_state[:test_block].call(entry)
|
335
|
+
# process link
|
336
|
+
if entry[:type].eql?('link')
|
337
|
+
sub_node_info=self.read("nodes/#{entry['target_node_id']}")[:data]
|
338
|
+
sub_opt={method: process_find_files, top_file_id: entry['target_id'], top_file_path: path}
|
339
|
+
get_node_api(sub_node_info,SCOPE_NODE_USER).crawl(self,sub_opt)
|
340
|
+
end
|
341
|
+
rescue => e
|
342
|
+
Log.log.error("#{path}: #{e.message}")
|
343
|
+
end
|
344
|
+
# process all folders
|
345
|
+
return true
|
335
346
|
end
|
336
347
|
|
337
|
-
# @returns list of file paths that match given regex
|
338
348
|
def find_files( top_node_file, test_block )
|
339
349
|
top_node_info,top_file_id=check_get_node_file(top_node_file)
|
340
350
|
Log.log.debug("find_files: node_info=#{top_node_info}, fileid=#{top_file_id}")
|
341
|
-
|
342
|
-
|
343
|
-
|
344
|
-
|
345
|
-
|
346
|
-
|
347
|
-
|
348
|
-
|
349
|
-
|
350
|
-
|
351
|
-
|
352
|
-
|
353
|
-
|
354
|
-
|
355
|
-
|
351
|
+
@find_state={found: [], test_block: test_block}
|
352
|
+
get_node_api(top_node_info,SCOPE_NODE_USER).crawl(self,{method: :process_find_files, top_file_id: top_file_id})
|
353
|
+
result=@find_state[:found]
|
354
|
+
@find_state=nil
|
355
|
+
return result
|
356
|
+
end
|
357
|
+
|
358
|
+
def process_resolve_node_file(entry,path)
|
359
|
+
# stop digging here if not in right path
|
360
|
+
return false unless entry['name'].eql?(@resolve_state[:path].first)
|
361
|
+
# ok it matches, so we remove the match
|
362
|
+
@resolve_state[:path].shift
|
363
|
+
case entry['type']
|
364
|
+
when 'file'
|
365
|
+
# file must be terminal
|
366
|
+
raise "#{entry['name']} is a file, expecting folder to find: #{@resolve_state[:path]}" unless @resolve_state[:path].empty?
|
367
|
+
@resolve_state[:result][:file_id]=entry['id']
|
368
|
+
when 'link'
|
369
|
+
@resolve_state[:result][:node_info]=self.read("nodes/#{entry['target_node_id']}")[:data]
|
370
|
+
if @resolve_state[:path].empty?
|
371
|
+
@resolve_state[:result][:file_id]=entry['target_id']
|
372
|
+
else
|
373
|
+
get_node_api(@resolve_state[:result][:node_info],SCOPE_NODE_USER).crawl(self,{method: :process_resolve_node_file, top_file_id: entry['target_id']})
|
356
374
|
end
|
357
|
-
|
358
|
-
|
359
|
-
|
360
|
-
|
361
|
-
|
362
|
-
begin
|
363
|
-
# does item match ?
|
364
|
-
result.push(current_file_info.merge({'path'=>item_path})) if test_block.call(current_file_info)
|
365
|
-
# does it need further processing ?
|
366
|
-
case current_file_info['type']
|
367
|
-
when 'file'
|
368
|
-
Log.log.debug("testing : #{current_file_info['name']}")
|
369
|
-
when 'folder'
|
370
|
-
items_to_explore.push({:node_api=>current_item[:node_api],:folder_id=>current_file_info['id'],:path=>item_path})
|
371
|
-
when 'link' # .*.asp-lnk
|
372
|
-
items_to_explore.push(read_asplnk(current_file_info).merge({:path=>item_path}))
|
373
|
-
else
|
374
|
-
Log.log.error("unknown folder item type: #{current_file_info['type']}")
|
375
|
-
end
|
376
|
-
rescue => e
|
377
|
-
Log.log.error("#{item_path}: #{e.message}")
|
378
|
-
end
|
375
|
+
when 'folder'
|
376
|
+
if @resolve_state[:path].empty?
|
377
|
+
# found: store
|
378
|
+
@resolve_state[:result][:file_id]=entry['id']
|
379
|
+
return false
|
379
380
|
end
|
381
|
+
else
|
382
|
+
Log.log.warn("unknown element type: #{entry['type']}")
|
380
383
|
end
|
381
|
-
|
384
|
+
# continue to dig folder
|
385
|
+
return true
|
382
386
|
end
|
383
387
|
|
384
|
-
# @return
|
388
|
+
# @return Array(node_info,file_id) for the given path
|
389
|
+
# @param top_node_file Array [root node,file id]
|
390
|
+
# @param element_path_string String path of element
|
385
391
|
# supports links to secondary nodes
|
386
|
-
|
387
|
-
|
388
|
-
|
389
|
-
|
390
|
-
|
391
|
-
|
392
|
-
|
393
|
-
|
394
|
-
|
395
|
-
|
396
|
-
|
397
|
-
|
398
|
-
current_node_api=get_node_api(current_node_info,SCOPE_NODE_USER) if current_node_api.nil?
|
399
|
-
# get folder content
|
400
|
-
folder_contents = current_node_api.read("files/#{current_file_id}/files")
|
401
|
-
Log.dump(:folder_contents,folder_contents)
|
402
|
-
matching_folders = folder_contents[:data].select { |i| i['name'].eql?(current_item)}
|
403
|
-
#Log.log.debug "matching_folders: #{matching_folders}"
|
404
|
-
raise "no such folder: #{current_item} in #{folder_contents[:data].map { |i| i['name']}}" if matching_folders.empty?
|
405
|
-
current_file_info = matching_folders.first
|
406
|
-
# process type of file
|
407
|
-
case current_file_info['type']
|
408
|
-
when 'file'
|
409
|
-
current_file_id=current_file_info['id']
|
410
|
-
# a file shall be terminal
|
411
|
-
if !items_to_explore.empty? then
|
412
|
-
raise "#{current_item} is a file, expecting folder to find: #{items_to_explore}"
|
413
|
-
end
|
414
|
-
when 'link'
|
415
|
-
current_node_info=self.read("nodes/#{current_file_info['target_node_id']}")[:data]
|
416
|
-
current_file_id=current_file_info['target_id']
|
417
|
-
# need to switch node
|
418
|
-
current_node_api=nil
|
419
|
-
when 'folder'
|
420
|
-
current_file_id=current_file_info['id']
|
421
|
-
else
|
422
|
-
Log.log.warn("unknown element type: #{current_file_info['type']}")
|
423
|
-
end
|
392
|
+
def resolve_node_file( top_node_file, element_path_string )
|
393
|
+
top_node_info,top_file_id=check_get_node_file(top_node_file)
|
394
|
+
path_elements=element_path_string.split(PATH_SEPARATOR).select{|i| !i.empty?}
|
395
|
+
result={node_info: top_node_info, file_id: nil}
|
396
|
+
if path_elements.empty?
|
397
|
+
result[:file_id]=top_file_id
|
398
|
+
else
|
399
|
+
@resolve_state={path: path_elements, result: result}
|
400
|
+
get_node_api(top_node_info,SCOPE_NODE_USER).crawl(self,{method: :process_resolve_node_file, top_file_id: top_file_id})
|
401
|
+
not_found=@resolve_state[:path]
|
402
|
+
@resolve_state=nil
|
403
|
+
raise "entry not found: #{not_found}" if result[:file_id].nil?
|
424
404
|
end
|
425
|
-
|
426
|
-
return {node_info: current_node_info, file_id: current_file_id}
|
405
|
+
return result
|
427
406
|
end
|
428
407
|
|
429
408
|
end # AoC
|
data/lib/aspera/cli/formater.rb
CHANGED
@@ -151,6 +151,8 @@ module Aspera
|
|
151
151
|
else
|
152
152
|
if user_asked_fields_list_str.start_with?('+')
|
153
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)}
|
154
156
|
else
|
155
157
|
user_asked_fields_list_str.split(',')
|
156
158
|
end
|