aspera-cli 4.13.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 +81 -7
- data/CONTRIBUTING.md +22 -6
- data/README.md +2038 -1080
- data/bin/ascli +18 -9
- data/bin/asession +12 -14
- data/examples/dascli +1 -1
- data/examples/proxy.pac +1 -1
- data/examples/rubyc +24 -0
- data/lib/aspera/aoc.rb +219 -159
- data/lib/aspera/ascmd.rb +25 -14
- data/lib/aspera/cli/basic_auth_plugin.rb +12 -9
- data/lib/aspera/cli/error.rb +17 -0
- data/lib/aspera/cli/extended_value.rb +47 -12
- data/lib/aspera/cli/formatter.rb +260 -179
- data/lib/aspera/cli/hints.rb +80 -0
- data/lib/aspera/cli/main.rb +104 -156
- data/lib/aspera/cli/manager.rb +259 -209
- data/lib/aspera/cli/plugin.rb +123 -63
- data/lib/aspera/cli/plugins/alee.rb +2 -3
- data/lib/aspera/cli/plugins/aoc.rb +341 -261
- data/lib/aspera/cli/plugins/ats.rb +22 -21
- data/lib/aspera/cli/plugins/bss.rb +5 -5
- data/lib/aspera/cli/plugins/config.rb +578 -627
- data/lib/aspera/cli/plugins/console.rb +44 -6
- data/lib/aspera/cli/plugins/cos.rb +15 -17
- data/lib/aspera/cli/plugins/faspex.rb +114 -100
- data/lib/aspera/cli/plugins/faspex5.rb +411 -264
- data/lib/aspera/cli/plugins/node.rb +354 -259
- data/lib/aspera/cli/plugins/orchestrator.rb +61 -29
- data/lib/aspera/cli/plugins/preview.rb +82 -90
- data/lib/aspera/cli/plugins/server.rb +79 -32
- data/lib/aspera/cli/plugins/shares.rb +55 -42
- data/lib/aspera/cli/sync_actions.rb +68 -0
- data/lib/aspera/cli/transfer_agent.rb +66 -73
- data/lib/aspera/cli/transfer_progress.rb +74 -0
- data/lib/aspera/cli/version.rb +1 -1
- data/lib/aspera/colors.rb +12 -8
- data/lib/aspera/command_line_builder.rb +14 -11
- data/lib/aspera/cos_node.rb +3 -2
- data/lib/aspera/data/6 +0 -0
- data/lib/aspera/environment.rb +24 -9
- 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 +25 -21
- data/lib/aspera/fasp/agent_direct.rb +89 -103
- data/lib/aspera/fasp/agent_httpgw.rb +231 -149
- data/lib/aspera/fasp/agent_node.rb +41 -34
- data/lib/aspera/fasp/agent_trsdk.rb +75 -32
- data/lib/aspera/fasp/error_info.rb +4 -2
- data/lib/aspera/fasp/faux_file.rb +52 -0
- data/lib/aspera/fasp/installation.rb +53 -195
- data/lib/aspera/fasp/management.rb +244 -0
- data/lib/aspera/fasp/parameters.rb +71 -37
- data/lib/aspera/fasp/parameters.yaml +76 -8
- data/lib/aspera/fasp/products.rb +162 -0
- data/lib/aspera/fasp/resume_policy.rb +3 -3
- data/lib/aspera/fasp/transfer_spec.rb +7 -6
- data/lib/aspera/fasp/uri.rb +26 -24
- data/lib/aspera/faspex_gw.rb +2 -2
- data/lib/aspera/faspex_postproc.rb +2 -2
- data/lib/aspera/hash_ext.rb +14 -4
- data/lib/aspera/json_rpc.rb +49 -0
- data/lib/aspera/keychain/macos_security.rb +13 -13
- data/lib/aspera/line_logger.rb +23 -0
- data/lib/aspera/log.rb +58 -16
- data/lib/aspera/node.rb +157 -92
- data/lib/aspera/oauth.rb +37 -19
- data/lib/aspera/open_application.rb +4 -4
- data/lib/aspera/persistency_action_once.rb +1 -1
- 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 +73 -16
- data/lib/aspera/preview/utils.rb +21 -28
- data/lib/aspera/proxy_auto_config.js +2 -2
- data/lib/aspera/rest.rb +136 -68
- 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 +18 -15
- data/lib/aspera/ssh.rb +5 -2
- data/lib/aspera/sync.rb +127 -119
- 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 +34 -17
- metadata.gz.sig +0 -0
- data/docs/test_env.conf +0 -186
- 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/data/7 +0 -0
- 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
|
@@ -127,7 +137,8 @@ module Aspera
|
|
127
137
|
byte_array = buffer.shift(num_bytes)
|
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)
|
141
|
+
Log.log.trace1{"#{' .' * indent_level}-> base:#{byte_array} -> #{result}"}
|
131
142
|
result = Time.at(result) if type_name.eql?(:epoch)
|
132
143
|
when :buffer_list
|
133
144
|
result = []
|
@@ -137,7 +148,7 @@ module Aspera
|
|
137
148
|
raise 'ERROR:not enough bytes' if buffer.length < length
|
138
149
|
value = buffer.shift(length)
|
139
150
|
result.push({btype: btype, buffer: value})
|
140
|
-
Log.log.
|
151
|
+
Log.log.trace1{"#{' .' * indent_level}:buffer_list[#{result.length - 1}] #{result.last}"}
|
141
152
|
end
|
142
153
|
when :field_list
|
143
154
|
# by default the result is one struct
|
@@ -146,13 +157,13 @@ module Aspera
|
|
146
157
|
parse(buffer, :blist, indent_level).each do |typed_buffer|
|
147
158
|
# what type of field is it ?
|
148
159
|
field_info = field_description(type_name, typed_buffer)
|
149
|
-
Log.log.
|
160
|
+
Log.log.trace1{"#{' .' * indent_level}+ field(special=#{field_info[:special]})=#{field_info[:name]}".green}
|
150
161
|
case field_info[:special]
|
151
162
|
when nil
|
152
163
|
result[field_info[:name]] = parse(typed_buffer[:buffer], field_info[:is_a], indent_level)
|
153
164
|
when :return_true
|
154
165
|
result[field_info[:name]] = true
|
155
|
-
when :
|
166
|
+
when :sub_struct
|
156
167
|
result[field_info[:name]] = parse(typed_buffer[:buffer], :blist, indent_level).map{|r|parse(r[:buffer], field_info[:is_a], indent_level)}
|
157
168
|
when :multiple
|
158
169
|
result[field_info[:name]] ||= []
|
@@ -8,29 +8,32 @@ 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
|
25
28
|
def basic_auth_params(subpath=nil)
|
26
|
-
api_url = options.get_option(:url,
|
29
|
+
api_url = options.get_option(:url, mandatory: true)
|
27
30
|
api_url = api_url + '/' + subpath unless subpath.nil?
|
28
31
|
return {
|
29
32
|
base_url: api_url,
|
30
33
|
auth: {
|
31
34
|
type: :basic,
|
32
|
-
username: options.get_option(:username,
|
33
|
-
password: options.get_option(:password,
|
35
|
+
username: options.get_option(:username, mandatory: true),
|
36
|
+
password: options.get_option(:password, mandatory: true)
|
34
37
|
}}
|
35
38
|
end
|
36
39
|
|
@@ -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
|