aspera-cli 4.5.0 → 4.8.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- checksums.yaml.gz.sig +1 -0
- data/README.md +1894 -1574
- data/bin/ascli +21 -1
- data/bin/asession +38 -34
- data/docs/test_env.conf +14 -3
- data/examples/aoc.rb +17 -15
- data/examples/dascli +26 -0
- data/examples/faspex4.rb +42 -35
- data/examples/proxy.pac +1 -1
- data/examples/transfer.rb +38 -37
- data/lib/aspera/aoc.rb +245 -205
- data/lib/aspera/ascmd.rb +111 -90
- data/lib/aspera/ats_api.rb +16 -14
- data/lib/aspera/cli/basic_auth_plugin.rb +19 -18
- data/lib/aspera/cli/extended_value.rb +50 -39
- data/lib/aspera/cli/formater.rb +161 -135
- data/lib/aspera/cli/info.rb +18 -0
- data/lib/aspera/cli/listener/line_dump.rb +4 -2
- data/lib/aspera/cli/listener/logger.rb +3 -1
- data/lib/aspera/cli/listener/progress.rb +20 -21
- data/lib/aspera/cli/listener/progress_multi.rb +29 -31
- data/lib/aspera/cli/main.rb +194 -183
- data/lib/aspera/cli/manager.rb +213 -206
- data/lib/aspera/cli/plugin.rb +71 -49
- data/lib/aspera/cli/plugins/alee.rb +8 -7
- data/lib/aspera/cli/plugins/aoc.rb +675 -558
- data/lib/aspera/cli/plugins/ats.rb +116 -109
- data/lib/aspera/cli/plugins/bss.rb +35 -34
- data/lib/aspera/cli/plugins/config.rb +722 -542
- data/lib/aspera/cli/plugins/console.rb +28 -22
- data/lib/aspera/cli/plugins/cos.rb +28 -37
- data/lib/aspera/cli/plugins/faspex.rb +281 -227
- data/lib/aspera/cli/plugins/faspex5.rb +129 -84
- data/lib/aspera/cli/plugins/node.rb +426 -232
- data/lib/aspera/cli/plugins/orchestrator.rb +106 -98
- data/lib/aspera/cli/plugins/preview.rb +196 -191
- data/lib/aspera/cli/plugins/server.rb +131 -126
- data/lib/aspera/cli/plugins/shares.rb +49 -36
- data/lib/aspera/cli/plugins/sync.rb +27 -28
- data/lib/aspera/cli/transfer_agent.rb +84 -79
- data/lib/aspera/cli/version.rb +3 -1
- data/lib/aspera/colors.rb +37 -28
- data/lib/aspera/command_line_builder.rb +84 -63
- data/lib/aspera/cos_node.rb +68 -34
- data/lib/aspera/data_repository.rb +4 -2
- data/lib/aspera/environment.rb +61 -46
- data/lib/aspera/fasp/agent_base.rb +36 -31
- data/lib/aspera/fasp/agent_connect.rb +44 -37
- data/lib/aspera/fasp/agent_direct.rb +101 -104
- data/lib/aspera/fasp/agent_httpgw.rb +91 -90
- data/lib/aspera/fasp/agent_node.rb +36 -33
- data/lib/aspera/fasp/agent_trsdk.rb +28 -31
- data/lib/aspera/fasp/error.rb +3 -1
- data/lib/aspera/fasp/error_info.rb +81 -54
- data/lib/aspera/fasp/installation.rb +171 -151
- data/lib/aspera/fasp/listener.rb +2 -0
- data/lib/aspera/fasp/parameters.rb +105 -111
- data/lib/aspera/fasp/parameters.yaml +305 -249
- data/lib/aspera/fasp/resume_policy.rb +20 -20
- data/lib/aspera/fasp/transfer_spec.rb +27 -0
- data/lib/aspera/fasp/uri.rb +31 -29
- data/lib/aspera/faspex_gw.rb +95 -118
- data/lib/aspera/hash_ext.rb +12 -13
- data/lib/aspera/id_generator.rb +11 -9
- data/lib/aspera/keychain/encrypted_hash.rb +73 -57
- data/lib/aspera/keychain/macos_security.rb +27 -29
- data/lib/aspera/log.rb +40 -39
- data/lib/aspera/nagios.rb +24 -22
- data/lib/aspera/node.rb +38 -30
- data/lib/aspera/oauth.rb +217 -248
- data/lib/aspera/open_application.rb +9 -7
- data/lib/aspera/persistency_action_once.rb +15 -14
- data/lib/aspera/persistency_folder.rb +15 -18
- data/lib/aspera/preview/file_types.rb +266 -270
- data/lib/aspera/preview/generator.rb +94 -92
- data/lib/aspera/preview/image_error.png +0 -0
- data/lib/aspera/preview/options.rb +20 -17
- data/lib/aspera/preview/utils.rb +99 -102
- data/lib/aspera/preview/video_error.png +0 -0
- data/lib/aspera/{proxy_auto_config.erb.js → proxy_auto_config.js} +23 -31
- data/lib/aspera/proxy_auto_config.rb +114 -21
- data/lib/aspera/rest.rb +144 -142
- data/lib/aspera/rest_call_error.rb +3 -2
- data/lib/aspera/rest_error_analyzer.rb +31 -31
- data/lib/aspera/rest_errors_aspera.rb +18 -16
- data/lib/aspera/secret_hider.rb +68 -0
- data/lib/aspera/ssh.rb +20 -16
- data/lib/aspera/sync.rb +57 -54
- data/lib/aspera/temp_file_manager.rb +20 -14
- data/lib/aspera/timer_limiter.rb +10 -8
- data/lib/aspera/uri_reader.rb +14 -15
- data/lib/aspera/web_auth.rb +85 -80
- data.tar.gz.sig +0 -0
- metadata +169 -40
- metadata.gz.sig +2 -0
- data/bin/dascli +0 -13
- data/docs/Makefile +0 -63
- data/docs/README.erb.md +0 -4221
- data/docs/README.md +0 -13
- data/docs/diagrams.txt +0 -49
- data/docs/doc_tools.rb +0 -58
- data/lib/aspera/cli/plugins/shares2.rb +0 -114
- data/lib/aspera/fasp/default.rb +0 -17
data/lib/aspera/ascmd.rb
CHANGED
@@ -1,3 +1,5 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
require 'aspera/log'
|
2
4
|
|
3
5
|
module Aspera
|
@@ -7,7 +9,7 @@ module Aspera
|
|
7
9
|
# Note: "ls" can take filters: as_ls -f *.txt -f *.bin /
|
8
10
|
class AsCmd
|
9
11
|
# list of supported actions
|
10
|
-
OPERATIONS=[
|
12
|
+
OPERATIONS = %i[ls rm mv du info mkdir cp df md5sum].freeze
|
11
13
|
|
12
14
|
# @param command_executor [Object] provides the "execute" method, taking a command to execute, and stdin to feed to it, typically: ssh or local
|
13
15
|
def initialize(command_executor)
|
@@ -20,132 +22,151 @@ module Aspera
|
|
20
22
|
# @return result of command, type depends on command (bool, array, hash)
|
21
23
|
def execute_single(action_sym,args=nil)
|
22
24
|
# concatenate arguments, enclose in double quotes, protect backslash and double quotes, add "as_" command and as_exit
|
23
|
-
stdin_input=(args||[]).map{|v| '"' + v.gsub(/["\\]/n) {|s| '\\' + s } + '"'}.unshift('as_'+action_sym.to_s).join(' ')+"\nas_exit\n"
|
25
|
+
stdin_input = (args || []).map{|v| '"' + v.gsub(/["\\]/n) {|s| '\\' + s } + '"'}.unshift('as_' + action_sym.to_s).join(' ') + "\nas_exit\n"
|
24
26
|
# execute, get binary output
|
25
|
-
bytebuffer
|
27
|
+
bytebuffer = @command_executor.execute('ascmd',stdin_input).unpack('C*')
|
26
28
|
# get hash or table result
|
27
|
-
result=self.class.parse(bytebuffer,:result)
|
28
|
-
raise
|
29
|
+
result = self.class.parse(bytebuffer,:result)
|
30
|
+
raise 'ERROR: unparsed bytes remaining' unless bytebuffer.empty?
|
29
31
|
# get and delete info,always present in results
|
30
|
-
system_info=result[:info]
|
32
|
+
system_info = result[:info]
|
31
33
|
result.delete(:info)
|
32
34
|
# make single file result like a folder
|
33
|
-
if result.has_key?(:file);result[:dir]=[result[:file]];result.delete(:file);end
|
35
|
+
if result.has_key?(:file);result[:dir] = [result[:file]];result.delete(:file);end
|
34
36
|
# add type field for stats
|
35
37
|
if result.has_key?(:dir)
|
36
38
|
result[:dir].each do |file|
|
37
39
|
if file.has_key?(:smode)
|
38
40
|
# Converts the first character of the file mode (see 'man ls') into a type.
|
39
|
-
file[:type]=case file[:smode][0,1];when'd'
|
41
|
+
file[:type] = case file[:smode][0,1];when 'd' then:directory;when '-' then:file;when 'l' then:link;else;:other;end
|
40
42
|
end
|
41
43
|
end
|
42
44
|
end
|
43
45
|
# for info, second overrides first, so restore it
|
44
|
-
case result.keys.length;when 0
|
46
|
+
case result.keys.length;when 0 then result = system_info;when 1 then result = result[result.keys.first];else raise 'error';end
|
45
47
|
# raise error as exception
|
46
|
-
raise Error.new(result[:errno],result[:errstr],action_sym,args) if
|
48
|
+
raise Error.new(result[:errno],result[:errstr],action_sym,args) if
|
49
|
+
result.is_a?(Hash) && (result.keys.sort == TYPES_DESCR[:error][:fields].map{|i|i[:name]}.sort)
|
47
50
|
return result
|
48
51
|
end # execute_single
|
49
52
|
|
50
53
|
# This exception is raised when +ascmd+ returns an error.
|
51
54
|
class Error < StandardError
|
52
55
|
attr_reader :errno, :errstr, :command, :args
|
53
|
-
def initialize(errno,errstr,cmd,args);@errno=errno;@errstr=errstr;@command=cmd;@args=args;end
|
56
|
+
def initialize(errno,errstr,cmd,args);super();@errno = errno;@errstr = errstr;@command = cmd;@args = args;end
|
54
57
|
|
55
58
|
def message; "ascmd: (#{errno}) #{errstr}"; end
|
56
59
|
|
57
60
|
def extended_message; "ascmd: errno=#{errno} errstr=\"#{errstr}\" command=\"#{command}\" args=#{args}"; end
|
58
61
|
end # Error
|
59
62
|
|
60
|
-
private
|
61
|
-
|
62
63
|
# description of result structures (see ascmdtypes.h). Base types are big endian
|
63
64
|
# key = name of type
|
64
|
-
TYPES_DESCR={
|
65
|
-
:
|
66
|
-
|
67
|
-
|
68
|
-
|
69
|
-
:
|
70
|
-
|
71
|
-
|
72
|
-
|
73
|
-
|
74
|
-
|
75
|
-
:
|
76
|
-
|
77
|
-
|
78
|
-
|
65
|
+
TYPES_DESCR = {
|
66
|
+
result: {decode: :field_list,
|
67
|
+
fields: [{name: :file,is_a: :stat},{name: :dir,is_a: :stat,special: :substruct},{name: :size,is_a: :size},{name: :error,is_a: :error},
|
68
|
+
{name: :info,is_a: :info},{name: :success,is_a: nil,special: :return_true},{name: :exit,is_a: nil},
|
69
|
+
{name: :df,is_a: :mnt,special: :restart_on_first},{name: :md5sum,is_a: :md5sum}]},
|
70
|
+
stat: {decode: :field_list,
|
71
|
+
fields: [{name: :name,is_a: :zstr},{name: :size,is_a: :int64},{name: :mode,is_a: :int32,check: nil},{name: :zmode,is_a: :zstr},
|
72
|
+
{name: :uid,is_a: :int32,check: nil},{name: :zuid,is_a: :zstr},{name: :gid,is_a: :int32,check: nil},{name: :zgid,is_a: :zstr},
|
73
|
+
{name: :ctime,is_a: :epoch},{name: :zctime,is_a: :zstr},{name: :mtime,is_a: :epoch},{name: :zmtime,is_a: :zstr},
|
74
|
+
{name: :atime,is_a: :epoch},{name: :zatime,is_a: :zstr},{name: :symlink,is_a: :zstr},{name: :errno,is_a: :int32},
|
75
|
+
{name: :errstr,is_a: :zstr}]},
|
76
|
+
info: {decode: :field_list,
|
77
|
+
fields: [{name: :platform,is_a: :zstr},{name: :version,is_a: :zstr},{name: :lang,is_a: :zstr},{name: :territory,is_a: :zstr},
|
78
|
+
{name: :codeset,is_a: :zstr},{name: :lc_ctype,is_a: :zstr},{name: :lc_numeric,is_a: :zstr},{name: :lc_time,is_a: :zstr},
|
79
|
+
{name: :lc_all,is_a: :zstr},{name: :dev,is_a: :zstr,special: :multiple},{name: :browse_caps,is_a: :zstr},
|
80
|
+
{name: :protocol,is_a: :zstr}]},
|
81
|
+
size: {decode: :field_list,
|
82
|
+
fields: [{name: :size,is_a: :int64},{name: :fcount,is_a: :int32},{name: :dcount,is_a: :int32},{name: :failed_fcount,is_a: :int32},
|
83
|
+
{name: :failed_dcount,is_a: :int32}]},
|
84
|
+
error: {decode: :field_list,
|
85
|
+
fields: [{name: :errno,is_a: :int32},{name: :errstr,is_a: :zstr}]},
|
86
|
+
mnt: {decode: :field_list,
|
87
|
+
fields: [{name: :fs,is_a: :zstr},{name: :dir,is_a: :zstr},{name: :is_a,is_a: :zstr},{name: :total,is_a: :int64},
|
88
|
+
{name: :used,is_a: :int64},{name: :free,is_a: :int64},{name: :fcount,is_a: :int64},{name: :errno,is_a: :int32},
|
89
|
+
{name: :errstr,is_a: :zstr}]},
|
90
|
+
md5sum: {decode: :field_list,fields: [{name: :md5sum,is_a: :zstr}]},
|
91
|
+
int8: {decode: :base,unpack: 'C',size: 1},
|
92
|
+
int32: {decode: :base,unpack: 'L>',size: 4},
|
93
|
+
int64: {decode: :base,unpack: 'Q>',size: 8},
|
94
|
+
epoch: {decode: :base,unpack: 'Q>',size: 8},
|
95
|
+
zstr: {decode: :base,unpack: 'Z*'},
|
96
|
+
blist: {decode: :buffer_list}
|
97
|
+
}.freeze
|
79
98
|
|
80
99
|
# protocol enum start at one, but array index start at zero
|
81
|
-
ENUM_START=1
|
100
|
+
ENUM_START = 1
|
82
101
|
|
83
102
|
private_constant :TYPES_DESCR,:ENUM_START
|
84
103
|
|
85
|
-
|
86
|
-
|
87
|
-
|
88
|
-
|
89
|
-
|
90
|
-
|
104
|
+
class << self
|
105
|
+
# get description of structure's field, @param struct_name, @param typed_buffer provides field name
|
106
|
+
def field_description(struct_name,typed_buffer)
|
107
|
+
result = TYPES_DESCR[struct_name][:fields][typed_buffer[:btype] - ENUM_START]
|
108
|
+
raise "Unrecognized field for #{struct_name}: #{typed_buffer[:btype]}\n#{typed_buffer[:buffer]}" if result.nil?
|
109
|
+
return result
|
110
|
+
end
|
91
111
|
|
92
|
-
|
93
|
-
|
94
|
-
|
95
|
-
|
96
|
-
|
97
|
-
|
98
|
-
|
99
|
-
|
100
|
-
|
101
|
-
|
102
|
-
|
103
|
-
|
104
|
-
|
105
|
-
|
106
|
-
|
107
|
-
|
108
|
-
|
109
|
-
|
110
|
-
|
111
|
-
|
112
|
-
|
113
|
-
|
114
|
-
|
115
|
-
|
116
|
-
|
117
|
-
|
118
|
-
|
119
|
-
|
120
|
-
|
121
|
-
|
122
|
-
|
123
|
-
|
124
|
-
|
125
|
-
|
126
|
-
|
127
|
-
|
128
|
-
|
129
|
-
|
130
|
-
|
131
|
-
|
132
|
-
|
133
|
-
|
134
|
-
|
135
|
-
|
136
|
-
|
137
|
-
|
138
|
-
|
139
|
-
|
140
|
-
|
141
|
-
|
142
|
-
|
112
|
+
# decodes the provided buffer as provided type name
|
113
|
+
# @return a decoded type.
|
114
|
+
# :base : value, :buffer_list : an array of {btype,buffer}, :field_list : a hash, or array
|
115
|
+
def parse(buffer,type_name,indent_level=nil)
|
116
|
+
indent_level = (indent_level || -1) + 1
|
117
|
+
type_descr = TYPES_DESCR[type_name]
|
118
|
+
raise "Unexpected type #{type_name}" if type_descr.nil?
|
119
|
+
Log.log.debug("#{' .' * indent_level}parse:#{type_name}:#{type_descr[:decode]}:#{buffer[0,16]}...".red)
|
120
|
+
result = nil
|
121
|
+
case type_descr[:decode]
|
122
|
+
when :base
|
123
|
+
num_bytes = type_name.eql?(:zstr) ? buffer.length : type_descr[:size]
|
124
|
+
raise 'ERROR:not enough bytes' if buffer.length < num_bytes
|
125
|
+
byte_array = buffer.shift(num_bytes);byte_array = [byte_array] unless byte_array.is_a?(Array)
|
126
|
+
result = byte_array.pack('C*').unpack1(type_descr[:unpack])
|
127
|
+
Log.log.debug("#{' .' * indent_level}-> base:#{byte_array} -> #{result}")
|
128
|
+
result = Time.at(result) if type_name.eql?(:epoch)
|
129
|
+
when :buffer_list
|
130
|
+
result = []
|
131
|
+
while !buffer.empty?
|
132
|
+
btype = parse(buffer,:int8,indent_level)
|
133
|
+
length = parse(buffer,:int32,indent_level)
|
134
|
+
raise 'ERROR:not enough bytes' if buffer.length < length
|
135
|
+
value = buffer.shift(length)
|
136
|
+
result.push({btype: btype,buffer: value})
|
137
|
+
Log.log.debug("#{' .' * indent_level}:buffer_list[#{result.length - 1}] #{result.last}")
|
138
|
+
end
|
139
|
+
when :field_list
|
140
|
+
# by default the result is one struct
|
141
|
+
result = {}
|
142
|
+
# get individual binary fields
|
143
|
+
parse(buffer,:blist,indent_level).each do |typed_buffer|
|
144
|
+
# what type of field is it ?
|
145
|
+
field_info = field_description(type_name,typed_buffer)
|
146
|
+
Log.log.debug("#{' .' * indent_level}+ field(special=#{field_info[:special]})=#{field_info[:name]}".green)
|
147
|
+
case field_info[:special]
|
148
|
+
when nil
|
149
|
+
result[field_info[:name]] = parse(typed_buffer[:buffer],field_info[:is_a],indent_level)
|
150
|
+
when :return_true
|
151
|
+
result[field_info[:name]] = true
|
152
|
+
when :substruct
|
153
|
+
result[field_info[:name]] = parse(typed_buffer[:buffer],:blist,indent_level).map{|r|parse(r[:buffer],field_info[:is_a],indent_level)}
|
154
|
+
when :multiple
|
155
|
+
result[field_info[:name]] ||= []
|
156
|
+
result[field_info[:name]].push(parse(typed_buffer[:buffer],field_info[:is_a],indent_level))
|
157
|
+
when :restart_on_first
|
158
|
+
fl = result[field_info[:name]] = []
|
159
|
+
parse(typed_buffer[:buffer],:blist,indent_level).map do |tb|
|
160
|
+
fl.push({}) if tb[:btype].eql?(ENUM_START)
|
161
|
+
fi = field_description(field_info[:is_a],tb)
|
162
|
+
fl.last[fi[:name]] = parse(tb[:buffer],fi[:is_a],indent_level)
|
163
|
+
end
|
143
164
|
end
|
144
165
|
end
|
145
|
-
|
146
|
-
|
147
|
-
|
148
|
-
|
166
|
+
else raise "error: unknown decode:#{type_descr[:decode]}"
|
167
|
+
end # is_a
|
168
|
+
return result
|
169
|
+
end
|
149
170
|
end
|
150
171
|
end
|
151
172
|
end
|
data/lib/aspera/ats_api.rb
CHANGED
@@ -1,3 +1,5 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
require 'aspera/log'
|
2
4
|
require 'aspera/rest'
|
3
5
|
|
@@ -5,32 +7,32 @@ module Aspera
|
|
5
7
|
class AtsApi < Rest
|
6
8
|
# currently supported clouds
|
7
9
|
# Note to Aspera: shall be an API call
|
8
|
-
CLOUD_NAME={
|
9
|
-
:
|
10
|
-
:
|
11
|
-
:
|
12
|
-
:
|
13
|
-
:
|
14
|
-
:
|
15
|
-
}
|
16
|
-
|
10
|
+
CLOUD_NAME = {
|
11
|
+
aws: 'Amazon Web Services',
|
12
|
+
azure: 'Microsoft Azure',
|
13
|
+
google: 'Google Cloud',
|
14
|
+
limelight: 'Limelight',
|
15
|
+
rackspace: 'Rackspace',
|
16
|
+
softlayer: 'IBM Cloud'
|
17
|
+
}.freeze
|
18
|
+
|
17
19
|
private_constant :CLOUD_NAME
|
18
|
-
|
20
|
+
|
19
21
|
def self.base_url;'https://ats.aspera.io';end
|
20
22
|
|
21
23
|
def initialize
|
22
|
-
super({:
|
24
|
+
super({base_url: AtsApi.base_url + '/pub/v1'})
|
23
25
|
# cache of server data
|
24
|
-
@all_servers_cache=nil
|
26
|
+
@all_servers_cache = nil
|
25
27
|
end
|
26
|
-
|
28
|
+
|
27
29
|
def cloud_names;CLOUD_NAME;end
|
28
30
|
|
29
31
|
# all available ATS servers
|
30
32
|
# NOTE to Aspera: an API shall be created to retrieve all servers at once
|
31
33
|
def all_servers
|
32
34
|
if @all_servers_cache.nil?
|
33
|
-
@all_servers_cache=[]
|
35
|
+
@all_servers_cache = []
|
34
36
|
CLOUD_NAME.keys.each do |name|
|
35
37
|
read("servers/#{name.to_s.upcase}")[:data].each do |i|
|
36
38
|
@all_servers_cache.push(i)
|
@@ -1,3 +1,5 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
require 'aspera/rest'
|
2
4
|
require 'aspera/cli/plugin'
|
3
5
|
|
@@ -5,34 +7,33 @@ module Aspera
|
|
5
7
|
module Cli
|
6
8
|
# base class for applications supporting basic authentication
|
7
9
|
class BasicAuthPlugin < Plugin
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
self.options.parse_options!
|
10
|
+
class << self
|
11
|
+
def register_options(env)
|
12
|
+
env[:options].add_opt_simple(:url,'URL of application, e.g. https://org.asperafiles.com')
|
13
|
+
env[:options].add_opt_simple(:username,'username to log in')
|
14
|
+
env[:options].add_opt_simple(:password,"user's password")
|
15
|
+
env[:options].parse_options!
|
15
16
|
end
|
16
17
|
end
|
17
|
-
ACTIONS=[]
|
18
18
|
|
19
|
-
def
|
20
|
-
|
19
|
+
def initialize(env)
|
20
|
+
super(env)
|
21
|
+
return if env[:skip_basic_auth_options]
|
22
|
+
self.class.register_options(env)
|
21
23
|
end
|
22
24
|
|
23
25
|
# returns a Rest object with basic auth
|
24
26
|
def basic_auth_api(subpath=nil)
|
25
|
-
api_url=
|
26
|
-
api_url=api_url+'/'+subpath unless subpath.nil?
|
27
|
+
api_url = options.get_option(:url,is_type: :mandatory)
|
28
|
+
api_url = api_url + '/' + subpath unless subpath.nil?
|
27
29
|
return Rest.new({
|
28
|
-
:
|
29
|
-
:
|
30
|
-
|
31
|
-
|
32
|
-
|
30
|
+
base_url: api_url,
|
31
|
+
auth: {
|
32
|
+
type: :basic,
|
33
|
+
username: options.get_option(:username,is_type: :mandatory),
|
34
|
+
password: options.get_option(:password,is_type: :mandatory)
|
33
35
|
}})
|
34
36
|
end
|
35
|
-
|
36
37
|
end # BasicAuthPlugin
|
37
38
|
end # Cli
|
38
39
|
end # Aspera
|
@@ -1,4 +1,8 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
require 'aspera/cli/plugins/config'
|
4
|
+
require 'aspera/uri_reader'
|
5
|
+
require 'aspera/environment'
|
2
6
|
require 'json'
|
3
7
|
require 'base64'
|
4
8
|
require 'zlib'
|
@@ -10,55 +14,62 @@ module Aspera
|
|
10
14
|
# command line extended values
|
11
15
|
class ExtendedValue
|
12
16
|
include Singleton
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
col_titles
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
|
17
|
+
|
18
|
+
class << self
|
19
|
+
# decode comma separated table text
|
20
|
+
def decode_csvt(value)
|
21
|
+
col_titles = nil
|
22
|
+
hasharray = []
|
23
|
+
CSV.parse(value).each do |values|
|
24
|
+
next if values.empty?
|
25
|
+
if col_titles.nil?
|
26
|
+
col_titles = values
|
27
|
+
else
|
28
|
+
entry = {}
|
29
|
+
col_titles.each{|title|entry[title] = values.shift}
|
30
|
+
hasharray.push(entry)
|
31
|
+
end
|
26
32
|
end
|
33
|
+
return hasharray
|
27
34
|
end
|
28
|
-
value=hasharray
|
29
35
|
end
|
30
36
|
|
37
|
+
private
|
38
|
+
|
31
39
|
def initialize
|
32
|
-
@handlers={
|
33
|
-
:
|
34
|
-
|
35
|
-
|
36
|
-
|
37
|
-
|
38
|
-
|
39
|
-
|
40
|
-
|
40
|
+
@handlers = {
|
41
|
+
decoder: {
|
42
|
+
base64: lambda{|v|Base64.decode64(v)},
|
43
|
+
json: lambda{|v|JSON.parse(v)},
|
44
|
+
zlib: lambda{|v|Zlib::Inflate.inflate(v)},
|
45
|
+
ruby: lambda{|v|Environment.secure_eval(v)},
|
46
|
+
csvt: lambda{|v|ExtendedValue.decode_csvt(v)},
|
47
|
+
lines: lambda{|v|v.split("\n")},
|
48
|
+
list: lambda{|v|v[1..-1].split(v[0])}
|
41
49
|
},
|
42
|
-
:
|
43
|
-
|
44
|
-
|
45
|
-
|
46
|
-
|
47
|
-
|
50
|
+
reader: {
|
51
|
+
val: lambda{|v|v},
|
52
|
+
file: lambda{|v|File.read(File.expand_path(v))},
|
53
|
+
path: lambda{|v|File.expand_path(v)},
|
54
|
+
env: lambda{|v|ENV[v]},
|
55
|
+
uri: lambda{|v|UriReader.read(v)},
|
56
|
+
stdin: lambda{|v|raise 'no value allowed for stdin' unless v.empty?;$stdin.read}
|
48
57
|
}
|
49
58
|
# other handlers can be set using set_handler, e.g. preset is reader in config plugin
|
50
59
|
}
|
51
60
|
end
|
61
|
+
|
52
62
|
public
|
53
63
|
|
54
|
-
def modifiers;@handlers.keys.map{|i|@handlers[i].keys}.flatten;end
|
64
|
+
def modifiers;@handlers.keys.map{|i|@handlers[i].keys}.flatten.map(&:to_s);end
|
55
65
|
|
56
66
|
# add a new :reader or :decoder
|
57
67
|
# decoder can be chained, reader is last one on right
|
58
68
|
def set_handler(name,type,method)
|
59
|
-
raise "type must be one of #{@handlers.keys}" unless @handlers.keys.include?(type)
|
60
69
|
Log.log.debug("setting #{type} handler for #{name}")
|
61
|
-
|
70
|
+
raise 'name must be Symbol' unless name.is_a?(Symbol)
|
71
|
+
raise "type #{type} must be one of #{@handlers.keys}" unless @handlers.key?(type)
|
72
|
+
@handlers[type][name] = method
|
62
73
|
end
|
63
74
|
|
64
75
|
# parse an option value if it is a String using supported extended value modifiers
|
@@ -66,20 +77,20 @@ module Aspera
|
|
66
77
|
def evaluate(value)
|
67
78
|
return value if !value.is_a?(String)
|
68
79
|
# first determine decoders, in reversed order
|
69
|
-
decoders_reversed=[]
|
70
|
-
while (m=value.match(/^@([^:]+):(.*)/))
|
71
|
-
decoders_reversed.unshift(m[1])
|
72
|
-
value=m[2]
|
80
|
+
decoders_reversed = []
|
81
|
+
while (m = value.match(/^@([^:]+):(.*)/)) && @handlers[:decoder].include?(m[1].to_sym)
|
82
|
+
decoders_reversed.unshift(m[1].to_sym)
|
83
|
+
value = m[2]
|
73
84
|
end
|
74
85
|
# then read value
|
75
86
|
@handlers[:reader].each do |reader,method|
|
76
|
-
if m=value.match(/^@#{reader}:(.*)/)
|
77
|
-
value=method.call(m[1])
|
87
|
+
if (m = value.match(/^@#{reader}:(.*)/))
|
88
|
+
value = method.call(m[1])
|
78
89
|
break
|
79
90
|
end
|
80
91
|
end
|
81
92
|
decoders_reversed.each do |decoder|
|
82
|
-
value
|
93
|
+
value = @handlers[:decoder][decoder].call(value)
|
83
94
|
end
|
84
95
|
return value
|
85
96
|
end # parse
|