aspera-cli 4.14.0 → 4.15.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 +0 -0
- data/CHANGELOG.md +54 -3
- data/CONTRIBUTING.md +7 -7
- data/README.md +1457 -880
- data/bin/ascli +18 -9
- data/bin/asession +12 -14
- data/examples/proxy.pac +1 -1
- data/lib/aspera/aoc.rb +198 -127
- data/lib/aspera/ascmd.rb +24 -14
- data/lib/aspera/cli/basic_auth_plugin.rb +9 -6
- data/lib/aspera/cli/error.rb +17 -0
- data/lib/aspera/cli/extended_value.rb +47 -12
- data/lib/aspera/cli/formatter.rb +260 -171
- data/lib/aspera/cli/hints.rb +80 -0
- data/lib/aspera/cli/main.rb +101 -147
- data/lib/aspera/cli/manager.rb +160 -124
- data/lib/aspera/cli/plugin.rb +70 -59
- data/lib/aspera/cli/plugins/alee.rb +0 -1
- data/lib/aspera/cli/plugins/aoc.rb +239 -273
- data/lib/aspera/cli/plugins/ats.rb +8 -5
- data/lib/aspera/cli/plugins/bss.rb +2 -2
- data/lib/aspera/cli/plugins/config.rb +516 -375
- data/lib/aspera/cli/plugins/console.rb +40 -0
- data/lib/aspera/cli/plugins/cos.rb +4 -5
- data/lib/aspera/cli/plugins/faspex.rb +99 -84
- data/lib/aspera/cli/plugins/faspex5.rb +179 -148
- data/lib/aspera/cli/plugins/node.rb +219 -153
- data/lib/aspera/cli/plugins/orchestrator.rb +52 -17
- data/lib/aspera/cli/plugins/preview.rb +46 -32
- data/lib/aspera/cli/plugins/server.rb +57 -17
- data/lib/aspera/cli/plugins/shares.rb +34 -12
- data/lib/aspera/cli/sync_actions.rb +68 -0
- data/lib/aspera/cli/transfer_agent.rb +45 -55
- data/lib/aspera/cli/transfer_progress.rb +74 -0
- data/lib/aspera/cli/version.rb +1 -1
- data/lib/aspera/colors.rb +3 -1
- data/lib/aspera/command_line_builder.rb +14 -11
- data/lib/aspera/cos_node.rb +3 -2
- data/lib/aspera/environment.rb +17 -6
- data/lib/aspera/fasp/agent_aspera.rb +126 -0
- data/lib/aspera/fasp/agent_base.rb +31 -77
- data/lib/aspera/fasp/agent_connect.rb +21 -22
- data/lib/aspera/fasp/agent_direct.rb +88 -102
- data/lib/aspera/fasp/agent_httpgw.rb +196 -192
- data/lib/aspera/fasp/agent_node.rb +41 -34
- data/lib/aspera/fasp/agent_trsdk.rb +75 -34
- data/lib/aspera/fasp/error_info.rb +2 -2
- data/lib/aspera/fasp/faux_file.rb +52 -0
- data/lib/aspera/fasp/installation.rb +43 -184
- data/lib/aspera/fasp/management.rb +244 -0
- data/lib/aspera/fasp/parameters.rb +59 -26
- data/lib/aspera/fasp/parameters.yaml +75 -8
- data/lib/aspera/fasp/products.rb +162 -0
- data/lib/aspera/fasp/transfer_spec.rb +1 -1
- data/lib/aspera/fasp/uri.rb +4 -4
- data/lib/aspera/faspex_gw.rb +2 -2
- data/lib/aspera/faspex_postproc.rb +2 -2
- data/lib/aspera/hash_ext.rb +2 -2
- data/lib/aspera/json_rpc.rb +49 -0
- data/lib/aspera/line_logger.rb +23 -0
- data/lib/aspera/log.rb +57 -16
- data/lib/aspera/node.rb +97 -14
- data/lib/aspera/oauth.rb +36 -18
- data/lib/aspera/open_application.rb +4 -4
- data/lib/aspera/persistency_folder.rb +2 -2
- data/lib/aspera/preview/file_types.rb +4 -2
- data/lib/aspera/preview/generator.rb +22 -35
- data/lib/aspera/preview/options.rb +2 -0
- data/lib/aspera/preview/terminal.rb +24 -13
- data/lib/aspera/preview/utils.rb +19 -26
- data/lib/aspera/rest.rb +103 -72
- data/lib/aspera/rest_call_error.rb +1 -1
- data/lib/aspera/rest_error_analyzer.rb +15 -14
- data/lib/aspera/rest_errors_aspera.rb +37 -34
- data/lib/aspera/secret_hider.rb +14 -16
- data/lib/aspera/ssh.rb +4 -1
- data/lib/aspera/sync.rb +128 -122
- data/lib/aspera/temp_file_manager.rb +10 -3
- data/lib/aspera/web_auth.rb +10 -7
- data/lib/aspera/web_server_simple.rb +9 -4
- data.tar.gz.sig +0 -0
- metadata +33 -15
- metadata.gz.sig +0 -0
- data/lib/aspera/cli/listener/line_dump.rb +0 -19
- data/lib/aspera/cli/listener/logger.rb +0 -22
- data/lib/aspera/cli/listener/progress.rb +0 -50
- data/lib/aspera/cli/listener/progress_multi.rb +0 -84
- data/lib/aspera/cli/plugins/sync.rb +0 -44
- data/lib/aspera/fasp/listener.rb +0 -13
data/lib/aspera/ascmd.rb
CHANGED
@@ -1,5 +1,6 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
+
# cspell:ignore ascmd smode errstr zstr zmode zuid zgid zctime zatime zmtime fcount dcount btype blist codeset lc_ctype ascmdtypes
|
3
4
|
require 'aspera/log'
|
4
5
|
|
5
6
|
module Aspera
|
@@ -20,9 +21,16 @@ module Aspera
|
|
20
21
|
# @param [Symbol] one of OPERATIONS
|
21
22
|
# @param [Array] parameters for "as" command
|
22
23
|
# @return result of command, type depends on command (bool, array, hash)
|
23
|
-
def execute_single(action_sym,
|
24
|
-
#
|
25
|
-
|
24
|
+
def execute_single(action_sym, arguments=nil)
|
25
|
+
# add "as_" command
|
26
|
+
main_command = ["as_#{action_sym}"]
|
27
|
+
arguments&.each do |v|
|
28
|
+
# enclose arguments in double quotes, protect backslash and double quotes
|
29
|
+
main_command.push(%Q{"#{v.gsub(/["\\]/n){|s|"\\#{s}"}}"})
|
30
|
+
end
|
31
|
+
# execute the main command and then exit
|
32
|
+
stdin_input = [main_command.join(' '), 'as_exit', ''].join("\n")
|
33
|
+
Log.log.debug{"execute_single:#{stdin_input}"}
|
26
34
|
# execute, get binary output
|
27
35
|
byte_buffer = @command_executor.execute('ascmd', stdin_input).unpack('C*')
|
28
36
|
raise 'ERROR: empty answer from server' if byte_buffer.empty?
|
@@ -46,27 +54,29 @@ module Aspera
|
|
46
54
|
# for info, second overrides first, so restore it
|
47
55
|
case result.keys.length; when 0 then result = system_info; when 1 then result = result[result.keys.first]; else raise 'error'; end
|
48
56
|
# raise error as exception
|
49
|
-
raise Error.new(result[:errno], result[:errstr], action_sym,
|
57
|
+
raise Error.new(result[:errno], result[:errstr], action_sym, arguments) if
|
50
58
|
result.is_a?(Hash) && (result.keys.sort == TYPES_DESCR[:error][:fields].map{|i|i[:name]}.sort)
|
51
59
|
return result
|
52
60
|
end # execute_single
|
53
61
|
|
54
62
|
# This exception is raised when +ascmd+ returns an error.
|
55
63
|
class Error < StandardError
|
56
|
-
|
64
|
+
def initialize(errno, errstr, cmd, arguments)
|
65
|
+
super(); @errno = errno; @errstr = errstr; @command = cmd; @arguments = arguments; end # rubocop:disable Style/Semicolon
|
57
66
|
|
58
|
-
def
|
67
|
+
def message; "ascmd: #{@errstr} (#{@errno})"; end
|
59
68
|
|
60
|
-
|
69
|
+
# TODO : delete : attr_reader :errno #, :errstr, :command
|
70
|
+
# TODO : delete :def args; @arguments; end
|
61
71
|
|
62
|
-
def extended_message; "ascmd: errno=#{errno} errstr=\"#{errstr}\" command
|
72
|
+
def extended_message; "ascmd: errno=#{@errno} errstr=\"#{@errstr}\" command=#{@command} arguments=#{@arguments.join(',')}"; end
|
63
73
|
end # Error
|
64
74
|
|
65
75
|
# description of result structures (see ascmdtypes.h). Base types are big endian
|
66
76
|
# key = name of type
|
67
77
|
TYPES_DESCR = {
|
68
78
|
result: {decode: :field_list,
|
69
|
-
fields: [{name: :file, is_a: :stat}, {name: :dir, is_a: :stat, special: :
|
79
|
+
fields: [{name: :file, is_a: :stat}, {name: :dir, is_a: :stat, special: :sub_struct}, {name: :size, is_a: :size}, {name: :error, is_a: :error},
|
70
80
|
{name: :info, is_a: :info}, {name: :success, is_a: nil, special: :return_true}, {name: :exit, is_a: nil},
|
71
81
|
{name: :df, is_a: :mnt, special: :restart_on_first}, {name: :md5sum, is_a: :md5sum}]},
|
72
82
|
stat: {decode: :field_list,
|
@@ -118,7 +128,7 @@ module Aspera
|
|
118
128
|
indent_level = (indent_level || -1) + 1
|
119
129
|
type_descr = TYPES_DESCR[type_name]
|
120
130
|
raise "Unexpected type #{type_name}" if type_descr.nil?
|
121
|
-
Log.log.
|
131
|
+
Log.log.trace1{"#{' .' * indent_level}parse:#{type_name}:#{type_descr[:decode]}:#{buffer[0, 16]}...".red}
|
122
132
|
result = nil
|
123
133
|
case type_descr[:decode]
|
124
134
|
when :base
|
@@ -128,7 +138,7 @@ module Aspera
|
|
128
138
|
byte_array = [byte_array] unless byte_array.is_a?(Array)
|
129
139
|
result = byte_array.pack('C*').unpack1(type_descr[:unpack])
|
130
140
|
result.force_encoding('UTF-8') if type_name.eql?(:zstr)
|
131
|
-
Log.log.
|
141
|
+
Log.log.trace1{"#{' .' * indent_level}-> base:#{byte_array} -> #{result}"}
|
132
142
|
result = Time.at(result) if type_name.eql?(:epoch)
|
133
143
|
when :buffer_list
|
134
144
|
result = []
|
@@ -138,7 +148,7 @@ module Aspera
|
|
138
148
|
raise 'ERROR:not enough bytes' if buffer.length < length
|
139
149
|
value = buffer.shift(length)
|
140
150
|
result.push({btype: btype, buffer: value})
|
141
|
-
Log.log.
|
151
|
+
Log.log.trace1{"#{' .' * indent_level}:buffer_list[#{result.length - 1}] #{result.last}"}
|
142
152
|
end
|
143
153
|
when :field_list
|
144
154
|
# by default the result is one struct
|
@@ -147,13 +157,13 @@ module Aspera
|
|
147
157
|
parse(buffer, :blist, indent_level).each do |typed_buffer|
|
148
158
|
# what type of field is it ?
|
149
159
|
field_info = field_description(type_name, typed_buffer)
|
150
|
-
Log.log.
|
160
|
+
Log.log.trace1{"#{' .' * indent_level}+ field(special=#{field_info[:special]})=#{field_info[:name]}".green}
|
151
161
|
case field_info[:special]
|
152
162
|
when nil
|
153
163
|
result[field_info[:name]] = parse(typed_buffer[:buffer], field_info[:is_a], indent_level)
|
154
164
|
when :return_true
|
155
165
|
result[field_info[:name]] = true
|
156
|
-
when :
|
166
|
+
when :sub_struct
|
157
167
|
result[field_info[:name]] = parse(typed_buffer[:buffer], :blist, indent_level).map{|r|parse(r[:buffer], field_info[:is_a], indent_level)}
|
158
168
|
when :multiple
|
159
169
|
result[field_info[:name]] ||= []
|
@@ -8,17 +8,20 @@ module Aspera
|
|
8
8
|
# base class for applications supporting basic authentication
|
9
9
|
class BasicAuthPlugin < Aspera::Cli::Plugin
|
10
10
|
class << self
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
11
|
+
@@basic_options_declared = false # rubocop:disable Style/ClassVars
|
12
|
+
def declare_options(options, force: false)
|
13
|
+
return if @@basic_options_declared && !force
|
14
|
+
@@basic_options_declared = true # rubocop:disable Style/ClassVars
|
15
|
+
options.declare(:url, 'URL of application, e.g. https://faspex.example.com/aspera/faspex')
|
16
|
+
options.declare(:username, 'Username to log in')
|
17
|
+
options.declare(:password, "User's password")
|
18
|
+
options.parse_options!
|
16
19
|
end
|
17
20
|
end
|
18
21
|
|
19
22
|
def initialize(env)
|
20
23
|
super(env)
|
21
|
-
|
24
|
+
BasicAuthPlugin.declare_options(options, force: env[:all_manuals])
|
22
25
|
end
|
23
26
|
|
24
27
|
# returns a Rest object with basic auth
|
@@ -0,0 +1,17 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Aspera
|
4
|
+
module Cli
|
5
|
+
# CLI base exception
|
6
|
+
class Error < StandardError; end
|
7
|
+
|
8
|
+
# raised when an unexpected argument is provided
|
9
|
+
class BadArgument < Error; end
|
10
|
+
|
11
|
+
class NoSuchIdentifier < Error
|
12
|
+
def initialize(res_type, res_id)
|
13
|
+
super("#{res_type} with identifier #{res_id} not found")
|
14
|
+
end
|
15
|
+
end
|
16
|
+
end
|
17
|
+
end
|
@@ -1,7 +1,9 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
+
# cspell:ignore csvt jsonpp
|
3
4
|
require 'aspera/uri_reader'
|
4
5
|
require 'aspera/environment'
|
6
|
+
require 'aspera/log'
|
5
7
|
require 'json'
|
6
8
|
require 'base64'
|
7
9
|
require 'zlib'
|
@@ -14,6 +16,10 @@ module Aspera
|
|
14
16
|
class ExtendedValue
|
15
17
|
include Singleton
|
16
18
|
|
19
|
+
# special values
|
20
|
+
ALL = 'ALL'
|
21
|
+
DEF = 'DEF'
|
22
|
+
|
17
23
|
class << self
|
18
24
|
# decode comma separated table text
|
19
25
|
def decode_csvt(value)
|
@@ -32,27 +38,36 @@ module Aspera
|
|
32
38
|
Log.log.warn('Titled CSV file without any line') if hash_array.empty?
|
33
39
|
return hash_array
|
34
40
|
end
|
41
|
+
|
42
|
+
def assert_no_value(v, what)
|
43
|
+
raise "no value allowed for extended value type: #{what}" unless v.empty?
|
44
|
+
end
|
35
45
|
end
|
36
46
|
|
37
47
|
private
|
38
48
|
|
39
49
|
def initialize
|
50
|
+
# base handlers
|
51
|
+
# other handlers can be set using set_handler, e.g. `preset` is reader in config plugin
|
40
52
|
@handlers = {
|
53
|
+
val: lambda{|v|v},
|
41
54
|
base64: lambda{|v|Base64.decode64(v)},
|
42
55
|
csvt: lambda{|v|ExtendedValue.decode_csvt(v)},
|
43
|
-
env: lambda{|v|ENV
|
56
|
+
env: lambda{|v|ENV.fetch(v, nil)},
|
44
57
|
file: lambda{|v|File.read(File.expand_path(v))},
|
58
|
+
uri: lambda{|v|UriReader.read(v)},
|
45
59
|
json: lambda{|v|JSON.parse(v)},
|
46
60
|
lines: lambda{|v|v.split("\n")},
|
47
61
|
list: lambda{|v|v[1..-1].split(v[0])},
|
62
|
+
none: lambda{|v|ExtendedValue.assert_no_value(v, :none); nil}, # rubocop:disable Style/Semicolon
|
48
63
|
path: lambda{|v|File.expand_path(v)},
|
49
|
-
|
50
|
-
|
51
|
-
|
52
|
-
|
53
|
-
|
54
|
-
zlib: lambda{|v|Zlib::Inflate.inflate(v)}
|
55
|
-
|
64
|
+
re: lambda{|v|Regexp.new(v)},
|
65
|
+
ruby: lambda{|v|Environment.secure_eval(v, __FILE__, __LINE__)},
|
66
|
+
secret: lambda{|v|ExtendedValue.assert_no_value(v, :secret); $stdin.getpass('secret> ')}, # rubocop:disable Style/Semicolon
|
67
|
+
stdin: lambda{|v|ExtendedValue.assert_no_value(v, :stdin); $stdin.read}, # rubocop:disable Style/Semicolon
|
68
|
+
yaml: lambda{|v|YAML.load(v)},
|
69
|
+
zlib: lambda{|v|Zlib::Inflate.inflate(v)},
|
70
|
+
extend: lambda{|v|ExtendedValue.instance.evaluate_all(v)}
|
56
71
|
}
|
57
72
|
end
|
58
73
|
|
@@ -67,21 +82,41 @@ module Aspera
|
|
67
82
|
@handlers[name] = method
|
68
83
|
end
|
69
84
|
|
85
|
+
# Regex to match an extended value
|
86
|
+
def ext_re
|
87
|
+
"@(#{modifiers.join('|')}):"
|
88
|
+
end
|
89
|
+
|
70
90
|
# parse an option value if it is a String using supported extended value modifiers
|
71
91
|
# other value types are returned as is
|
72
92
|
def evaluate(value)
|
73
|
-
return value
|
93
|
+
return value unless value.is_a?(String)
|
94
|
+
regex = Regexp.new("^#{ext_re}(.*)$")
|
74
95
|
# first determine decoders, in reversed order
|
75
96
|
handlers_reversed = []
|
76
|
-
while (m = value.match(
|
77
|
-
|
97
|
+
while (m = value.match(regex))
|
98
|
+
handler = m[1].to_sym
|
99
|
+
handlers_reversed.unshift(handler)
|
78
100
|
value = m[2]
|
101
|
+
# stop processing if handler is extend (it will be processed later)
|
102
|
+
break if handler.eql?(:extend)
|
79
103
|
end
|
80
104
|
handlers_reversed.each do |handler|
|
81
105
|
value = @handlers[handler].call(value)
|
82
106
|
end
|
83
107
|
return value
|
84
|
-
end #
|
108
|
+
end # evaluate
|
109
|
+
|
110
|
+
# find inner extended values
|
111
|
+
def evaluate_all(value)
|
112
|
+
regex = Regexp.new("^(.*)#{ext_re}([^@]*)@(.*)$")
|
113
|
+
while (m = value.match(regex))
|
114
|
+
sub_value = "@#{m[2]}:#{m[3]}"
|
115
|
+
Log.log.debug("evaluating #{sub_value}")
|
116
|
+
value = m[1] + evaluate(sub_value) + m[4]
|
117
|
+
end
|
118
|
+
return value
|
119
|
+
end
|
85
120
|
end
|
86
121
|
end
|
87
122
|
end
|