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