aspera-cli 4.23.0 → 4.24.1
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 +37 -1
- data/CONTRIBUTING.md +86 -29
- data/README.md +2109 -1300
- data/bin/ascli +2 -1
- data/bin/asession +4 -4
- data/lib/aspera/agent/base.rb +4 -0
- data/lib/aspera/agent/connect.rb +20 -18
- data/lib/aspera/agent/desktop.rb +14 -11
- data/lib/aspera/agent/direct.rb +39 -31
- data/lib/aspera/agent/httpgw.rb +2 -2
- data/lib/aspera/agent/node.rb +9 -11
- data/lib/aspera/agent/transferd.rb +18 -11
- data/lib/aspera/api/aoc.rb +44 -31
- data/lib/aspera/api/cos_node.rb +7 -5
- data/lib/aspera/api/httpgw.rb +15 -18
- data/lib/aspera/api/node.rb +104 -22
- data/lib/aspera/ascmd.rb +22 -16
- data/lib/aspera/ascp/installation.rb +37 -40
- data/lib/aspera/ascp/management.rb +5 -4
- data/lib/aspera/assert.rb +54 -23
- data/lib/aspera/cli/basic_auth_plugin.rb +8 -7
- data/lib/aspera/cli/error.rb +1 -1
- data/lib/aspera/cli/extended_value.rb +28 -29
- data/lib/aspera/cli/formatter.rb +191 -168
- data/lib/aspera/cli/hints.rb +29 -3
- data/lib/aspera/cli/main.rb +138 -107
- data/lib/aspera/cli/manager.rb +50 -30
- data/lib/aspera/cli/plugin.rb +148 -77
- data/lib/aspera/cli/plugin_factory.rb +2 -2
- data/lib/aspera/cli/plugins/aoc.rb +189 -70
- data/lib/aspera/cli/plugins/ats.rb +15 -13
- data/lib/aspera/cli/plugins/config.rb +100 -214
- data/lib/aspera/cli/plugins/console.rb +49 -18
- data/lib/aspera/cli/plugins/cos.rb +4 -4
- data/lib/aspera/cli/plugins/faspex.rb +45 -51
- data/lib/aspera/cli/plugins/faspex5.rb +164 -165
- data/lib/aspera/cli/plugins/faspio.rb +6 -5
- data/lib/aspera/cli/plugins/httpgw.rb +2 -2
- data/lib/aspera/cli/plugins/node.rb +144 -162
- data/lib/aspera/cli/plugins/orchestrator.rb +10 -14
- data/lib/aspera/cli/plugins/preview.rb +26 -29
- data/lib/aspera/cli/plugins/server.rb +28 -28
- data/lib/aspera/cli/plugins/shares.rb +40 -28
- data/lib/aspera/cli/sync_actions.rb +101 -80
- data/lib/aspera/cli/transfer_agent.rb +51 -50
- data/lib/aspera/cli/transfer_progress.rb +29 -20
- data/lib/aspera/cli/version.rb +1 -1
- data/lib/aspera/cli/wizard.rb +157 -0
- data/lib/aspera/colors.rb +13 -8
- data/lib/aspera/command_line_builder.rb +28 -22
- data/lib/aspera/command_line_converter.rb +31 -0
- data/lib/aspera/environment.rb +145 -101
- data/lib/aspera/faspex_gw.rb +1 -1
- data/lib/aspera/faspex_postproc.rb +3 -2
- data/lib/aspera/hash_ext.rb +1 -1
- data/lib/aspera/id_generator.rb +10 -10
- data/lib/aspera/keychain/base.rb +18 -0
- data/lib/aspera/keychain/encrypted_hash.rb +6 -12
- data/lib/aspera/keychain/factory.rb +9 -3
- data/lib/aspera/keychain/hashicorp_vault.rb +9 -6
- data/lib/aspera/keychain/macos_security.rb +13 -13
- data/lib/aspera/log.rb +91 -19
- data/lib/aspera/nagios.rb +5 -6
- data/lib/aspera/node_simulator.rb +12 -7
- data/lib/aspera/oauth/base.rb +5 -3
- data/lib/aspera/oauth/factory.rb +24 -18
- data/lib/aspera/oauth/jwt.rb +13 -1
- data/lib/aspera/oauth/url_json.rb +3 -3
- data/lib/aspera/oauth/web.rb +5 -3
- data/lib/aspera/persistency_folder.rb +2 -2
- data/lib/aspera/preview/file_types.rb +4 -3
- data/lib/aspera/preview/generator.rb +25 -12
- data/lib/aspera/preview/terminal.rb +10 -7
- data/lib/aspera/preview/utils.rb +11 -9
- data/lib/aspera/products/connect.rb +1 -1
- data/lib/aspera/products/desktop.rb +1 -1
- data/lib/aspera/products/other.rb +2 -2
- data/lib/aspera/products/transferd.rb +8 -6
- data/lib/aspera/proxy_auto_config.rb +1 -1
- data/lib/aspera/rest.rb +29 -22
- data/lib/aspera/rest_call_error.rb +1 -1
- data/lib/aspera/resumer.rb +1 -1
- data/lib/aspera/secret_hider.rb +46 -40
- data/lib/aspera/ssh.rb +13 -3
- data/lib/aspera/sync/args.schema.yaml +102 -0
- data/lib/aspera/sync/conf.schema.yaml +701 -0
- data/lib/aspera/sync/database.rb +83 -0
- data/lib/aspera/sync/operations.rb +296 -0
- data/lib/aspera/temp_file_manager.rb +3 -2
- data/lib/aspera/transfer/error.rb +1 -1
- data/lib/aspera/transfer/error_info.rb +1 -2
- data/lib/aspera/transfer/faux_file.rb +11 -10
- data/lib/aspera/transfer/parameters.rb +6 -5
- data/lib/aspera/transfer/spec.rb +15 -1
- data/lib/aspera/transfer/spec.schema.yaml +316 -293
- data/lib/aspera/transfer/spec_doc.rb +34 -16
- data/lib/aspera/transfer/uri.rb +5 -5
- data/lib/aspera/uri_reader.rb +14 -10
- data/lib/aspera/web_auth.rb +2 -2
- data/lib/aspera/web_server_simple.rb +2 -2
- data.tar.gz.sig +0 -0
- metadata +15 -13
- metadata.gz.sig +0 -0
- data/lib/aspera/transfer/async_conf.schema.yaml +0 -716
- data/lib/aspera/transfer/convert.rb +0 -29
- data/lib/aspera/transfer/sync.rb +0 -232
- data/lib/aspera/transfer/sync_instance.schema.yaml +0 -20
- data/lib/aspera/transfer/sync_session.schema.yaml +0 -86
data/lib/aspera/ascmd.rb
CHANGED
@@ -30,10 +30,16 @@ module Aspera
|
|
30
30
|
# Description of result structures (see ascmdtypes.h).
|
31
31
|
# Base types are big endian
|
32
32
|
# key = name of type
|
33
|
-
# index in array `fields` is the type
|
33
|
+
# index in array `fields` is: the numerical type of TLV - `ENUM_START`. i.e. add `ENUM_START` to index, to get `T`
|
34
34
|
# decoding always start at `result`
|
35
35
|
# some fields have special handling indicated by `special`
|
36
36
|
# field_list, list_tlv_list, list_tlv_restart are composed with a list of TLV
|
37
|
+
# decode:
|
38
|
+
# - :base : value
|
39
|
+
# - :buffer_list : an array of {btype,buffer}
|
40
|
+
# - :field_list : a hash, or array
|
41
|
+
# :check: ???
|
42
|
+
# rubocop:disable Layout/FirstHashElementLineBreak
|
37
43
|
TYPES_DESCR = {
|
38
44
|
result: {decode: :field_list,
|
39
45
|
fields: [{name: :file, is_a: :stat}, {name: :dir, is_a: :stat, special: :list_tlv_list}, {name: :size, is_a: :size}, {name: :error, is_a: :error},
|
@@ -67,6 +73,7 @@ module Aspera
|
|
67
73
|
zstr: {decode: :base, unpack: 'Z*'},
|
68
74
|
blist: {decode: :buffer_list}
|
69
75
|
}.freeze
|
76
|
+
# rubocop:enable Layout/FirstHashElementLineBreak
|
70
77
|
|
71
78
|
private_constant :TYPES_DESCR, :ENUM_START, :OPS_ARGS
|
72
79
|
|
@@ -122,11 +129,11 @@ module Aspera
|
|
122
129
|
stdin_input = command_lines.join("\n")
|
123
130
|
Log.log.trace1{"execute_single:#{stdin_input}"}
|
124
131
|
# execute, get binary output
|
125
|
-
byte_buffer = @command_executor.execute(remote_cmd, stdin_input).unpack('C*')
|
126
|
-
|
132
|
+
byte_buffer = @command_executor.execute(remote_cmd, input: stdin_input).unpack('C*')
|
133
|
+
Aspera.assert(!byte_buffer.empty?){'empty answer from server'}
|
127
134
|
# get hash or table result
|
128
135
|
result = self.class.parse(byte_buffer, :result)
|
129
|
-
|
136
|
+
Aspera.assert(byte_buffer.empty?){'unparsed bytes remaining'}
|
130
137
|
# get and delete info,always present in results
|
131
138
|
system_info = result[:info]
|
132
139
|
result.delete(:info)
|
@@ -137,7 +144,7 @@ module Aspera
|
|
137
144
|
result[:dir].each do |file|
|
138
145
|
if file.key?(:smode)
|
139
146
|
# Converts the first character of the file mode (see 'man ls') into a type.
|
140
|
-
file[:type] = case file[:smode][0, 1]; when 'd' then:directory; when '-' then:file; when 'l' then:link; else; :other; end
|
147
|
+
file[:type] = case file[:smode][0, 1]; when 'd' then:directory; when '-' then:file; when 'l' then:link; else; :other; end
|
141
148
|
end
|
142
149
|
end
|
143
150
|
end
|
@@ -153,27 +160,26 @@ module Aspera
|
|
153
160
|
return result
|
154
161
|
end
|
155
162
|
|
156
|
-
# This exception is raised when
|
163
|
+
# This exception is raised when `ascmd` returns an error.
|
157
164
|
class Error < StandardError
|
158
|
-
|
159
|
-
|
160
|
-
|
165
|
+
# rubocop:disable Style/Semicolon
|
166
|
+
def initialize(errno, errstr, cmd, arguments); super(); @errno = errno; @errstr = errstr; @command = cmd; @arguments = arguments; end
|
161
167
|
def message; "ascmd: #{@errstr} (#{@errno})"; end
|
162
168
|
def extended_message; "ascmd: errno=#{@errno} errstr=\"#{@errstr}\" command=#{@command} arguments=#{@arguments&.join(',')}"; end
|
169
|
+
# rubocop:enable Style/Semicolon
|
163
170
|
end
|
164
171
|
|
165
172
|
class << self
|
166
|
-
#
|
173
|
+
# Get description of structure's field, @param struct_name, @param typed_buffer provides field name
|
167
174
|
def field_description(struct_name, typed_buffer)
|
168
175
|
result = TYPES_DESCR[struct_name][:fields][typed_buffer[:btype] - ENUM_START]
|
169
176
|
raise "Unrecognized field for #{struct_name}: #{typed_buffer[:btype]}\n#{typed_buffer[:buffer]}" if result.nil?
|
170
177
|
return result
|
171
178
|
end
|
172
179
|
|
173
|
-
#
|
174
|
-
# @return a decoded type
|
175
|
-
|
176
|
-
def parse(buffer, type_name, indent_level=nil)
|
180
|
+
# Decodes the provided buffer as provided type name
|
181
|
+
# @return a decoded type: single, Array, or Hash
|
182
|
+
def parse(buffer, type_name, indent_level = nil)
|
177
183
|
indent_level = (indent_level || -1) + 1
|
178
184
|
type_descr = TYPES_DESCR[type_name]
|
179
185
|
raise "Unexpected type #{type_name}" if type_descr.nil?
|
@@ -182,7 +188,7 @@ module Aspera
|
|
182
188
|
case type_descr[:decode]
|
183
189
|
when :base
|
184
190
|
num_bytes = type_name.eql?(:zstr) ? buffer.length : type_descr[:size]
|
185
|
-
|
191
|
+
Aspera.assert(buffer.length >= num_bytes){'not enough bytes'}
|
186
192
|
byte_array = buffer.shift(num_bytes)
|
187
193
|
byte_array = [byte_array] unless byte_array.is_a?(Array)
|
188
194
|
result = byte_array.pack('C*').unpack1(type_descr[:unpack])
|
@@ -195,7 +201,7 @@ module Aspera
|
|
195
201
|
until buffer.empty?
|
196
202
|
btype = parse(buffer, :int8, indent_level)
|
197
203
|
length = parse(buffer, :int32, indent_level)
|
198
|
-
|
204
|
+
Aspera.assert(buffer.length >= length){'not enough bytes'}
|
199
205
|
value = buffer.shift(length)
|
200
206
|
result.push({btype: btype, buffer: value})
|
201
207
|
Log.log.trace1{"#{' .' * indent_level}:buffer_list[#{result.length - 1}] #{result.last}"}
|
@@ -44,12 +44,12 @@ module Aspera
|
|
44
44
|
</default>
|
45
45
|
</CONF>
|
46
46
|
END_OF_CONFIG_FILE
|
47
|
-
# all
|
48
|
-
EXE_FILES = %i[ascp ascp4 async].freeze
|
49
|
-
|
50
|
-
|
47
|
+
# all executable files from SDK
|
48
|
+
EXE_FILES = %i[ascp ascp4 async transferd].freeze
|
49
|
+
SDK_FILES = %i[ssh_private_dsa ssh_private_rsa aspera_license aspera_conf fallback_certificate fallback_private_key].unshift(*EXE_FILES).freeze
|
50
|
+
TRANSFERD_ARCHIVE_LOCATION_URL = 'https://ibm.biz/sdk_location'
|
51
51
|
# filename for ascp with optional extension (Windows)
|
52
|
-
private_constant :DEFAULT_ASPERA_CONF, :
|
52
|
+
private_constant :DEFAULT_ASPERA_CONF, :SDK_FILES, :TRANSFERD_ARCHIVE_LOCATION_URL
|
53
53
|
# options for SSH client private key
|
54
54
|
CLIENT_SSH_KEY_OPTIONS = %i{dsa_rsa rsa per_client}.freeze
|
55
55
|
|
@@ -99,7 +99,7 @@ module Aspera
|
|
99
99
|
|
100
100
|
# @return [Hash] with key = file name (String), and value = path to file
|
101
101
|
def file_paths
|
102
|
-
return
|
102
|
+
return SDK_FILES.each_with_object({}) do |v, m|
|
103
103
|
m[v.to_s] =
|
104
104
|
begin
|
105
105
|
path(v)
|
@@ -115,19 +115,23 @@ module Aspera
|
|
115
115
|
return Environment.write_file_restricted(File.join(Products::Transferd.sdk_directory, filename), force: force, mode: 0o644, &block)
|
116
116
|
end
|
117
117
|
|
118
|
-
#
|
118
|
+
# Get path of one resource file of currently activated product
|
119
119
|
# keys and certs are generated locally... (they are well known values, arch. independent)
|
120
|
+
# @param k [Symbol] key of the resource file
|
121
|
+
# @return [String, nil] Full path to the resource file or nil if not found
|
120
122
|
def path(k)
|
121
|
-
|
123
|
+
file_is_required = true
|
122
124
|
case k
|
123
125
|
when *EXE_FILES
|
124
|
-
|
125
|
-
|
126
|
-
|
127
|
-
|
128
|
-
|
129
|
-
|
130
|
-
|
126
|
+
file_is_required = k.eql?(:ascp)
|
127
|
+
file = if k.eql?(:transferd)
|
128
|
+
Products::Transferd.transferd_path
|
129
|
+
else
|
130
|
+
# ensure at least ascp is found
|
131
|
+
use_ascp_from_product(FIRST_FOUND) if @path_to_ascp.nil?
|
132
|
+
# NOTE: that there might be a .exe at the end
|
133
|
+
@path_to_ascp.gsub('ascp', k.to_s)
|
134
|
+
end
|
131
135
|
when :ssh_private_dsa, :ssh_private_rsa
|
132
136
|
# assume last 3 letters are type
|
133
137
|
type = k.to_s[-3..-1].to_sym
|
@@ -150,8 +154,8 @@ module Aspera
|
|
150
154
|
file = k.eql?(:fallback_certificate) ? file_cert : file_key
|
151
155
|
else Aspera.error_unexpected_value(k)
|
152
156
|
end
|
153
|
-
return
|
154
|
-
Aspera.assert(File.exist?(file),
|
157
|
+
return unless file_is_required || File.exist?(file)
|
158
|
+
Aspera.assert(File.exist?(file), type: Errno::ENOENT){"#{k} not found (#{file})"}
|
155
159
|
return file
|
156
160
|
end
|
157
161
|
|
@@ -168,7 +172,7 @@ module Aspera
|
|
168
172
|
when :dsa_rsa, :rsa
|
169
173
|
types.to_s.split('_').map{ |i| Installation.instance.path("ssh_private_#{i}".to_sym)}
|
170
174
|
when :per_client
|
171
|
-
|
175
|
+
Aspera.error_not_implemented
|
172
176
|
end
|
173
177
|
end
|
174
178
|
|
@@ -179,8 +183,9 @@ module Aspera
|
|
179
183
|
|
180
184
|
# Check that specified path is ascp and get version
|
181
185
|
def get_exe_version(exe_path, vers_arg)
|
182
|
-
|
183
|
-
|
186
|
+
Aspera.assert_type(exe_path, String)
|
187
|
+
Aspera.assert_type(vers_arg, String)
|
188
|
+
return unless File.exist?(exe_path)
|
184
189
|
exe_version = nil
|
185
190
|
cmd_out = %x("#{exe_path}" #{vers_arg})
|
186
191
|
raise "An error occurred when testing #{exe_path}: #{cmd_out}" unless $CHILD_STATUS == 0
|
@@ -217,9 +222,7 @@ module Aspera
|
|
217
222
|
data['ascp_version'] = Regexp.last_match(1)
|
218
223
|
end
|
219
224
|
end
|
220
|
-
if !thread.value.exitstatus.eql?(1) && !data.key?('root')
|
221
|
-
raise last_line
|
222
|
-
end
|
225
|
+
raise last_line if !thread.value.exitstatus.eql?(1) && !data.key?('root')
|
223
226
|
end
|
224
227
|
return data
|
225
228
|
end
|
@@ -248,7 +251,7 @@ module Aspera
|
|
248
251
|
# @return the url for download of SDK archive for the given platform and version
|
249
252
|
def sdk_url_for_platform(platform: nil, version: nil)
|
250
253
|
locations = sdk_locations
|
251
|
-
platform = Environment.architecture if platform.nil?
|
254
|
+
platform = Environment.instance.architecture if platform.nil?
|
252
255
|
locations = locations.select{ |l| l['platform'].eql?(platform)}
|
253
256
|
raise "No SDK for platform: #{platform}" if locations.empty?
|
254
257
|
version = locations.max_by{ |entry| Gem::Version.new(entry['version'])}['version'] if version.nil?
|
@@ -259,7 +262,7 @@ module Aspera
|
|
259
262
|
|
260
263
|
# @param &block called with entry information
|
261
264
|
def extract_archive_files(sdk_archive_path)
|
262
|
-
|
265
|
+
Aspera.assert(block_given?){'missing block'}
|
263
266
|
case sdk_archive_path
|
264
267
|
# Windows and Mac use zip
|
265
268
|
when /\.zip$/
|
@@ -330,21 +333,15 @@ module Aspera
|
|
330
333
|
end
|
331
334
|
end
|
332
335
|
return unless with_exe
|
333
|
-
# ensure
|
334
|
-
|
335
|
-
|
336
|
-
|
337
|
-
|
338
|
-
|
339
|
-
EXE_FILES.each do |exe_sym|
|
340
|
-
exe_path = sdk_ascp_path.gsub('ascp', exe_sym.to_s)
|
341
|
-
Environment.restrict_file_access(exe_path, mode: 0o755) if File.exist?(exe_path)
|
336
|
+
# ensure necessary files are there, or generate them
|
337
|
+
SDK_FILES.each do |file_id_sym|
|
338
|
+
file_path = path(file_id_sym)
|
339
|
+
if file_path && EXE_FILES.include?(file_id_sym)
|
340
|
+
Environment.restrict_file_access(file_path, mode: 0o755) if File.exist?(file_path)
|
341
|
+
end
|
342
342
|
end
|
343
|
-
sdk_ascp_version = get_ascp_version(
|
344
|
-
|
345
|
-
Log.log.warn{"No #{transferd_exe_path} in SDK archive"} unless File.exist?(transferd_exe_path)
|
346
|
-
Environment.restrict_file_access(transferd_exe_path, mode: 0o755) if File.exist?(transferd_exe_path)
|
347
|
-
transferd_version = get_exe_version(transferd_exe_path, 'version')
|
343
|
+
sdk_ascp_version = get_ascp_version(path(:ascp))
|
344
|
+
transferd_version = get_exe_version(path(:transferd), 'version')
|
348
345
|
sdk_name = 'IBM Aspera Transfer SDK'
|
349
346
|
sdk_version = transferd_version || sdk_ascp_version
|
350
347
|
File.write(File.join(folder, Products::Other::INFO_META_FILE), "<product><name>#{sdk_name}</name><version>#{sdk_version}</version></product>")
|
@@ -362,7 +359,7 @@ module Aspera
|
|
362
359
|
@path_to_ascp = nil
|
363
360
|
@sdk_dir = nil
|
364
361
|
@found_products = nil
|
365
|
-
@transferd_urls =
|
362
|
+
@transferd_urls = TRANSFERD_ARCHIVE_LOCATION_URL
|
366
363
|
end
|
367
364
|
|
368
365
|
public
|
@@ -184,7 +184,8 @@ module Aspera
|
|
184
184
|
ChunkSize
|
185
185
|
PostTransferValidation
|
186
186
|
OverwritePolicyCap
|
187
|
-
ExtraCreatePolicy
|
187
|
+
ExtraCreatePolicy
|
188
|
+
]
|
188
189
|
# Management port start message
|
189
190
|
MGT_HEADER = 'FASPMGR 2'
|
190
191
|
# empty line is separator to end event information
|
@@ -252,17 +253,17 @@ module Aspera
|
|
252
253
|
# begin event
|
253
254
|
@event_build = {}
|
254
255
|
when /^([^:]+): (.*)$/
|
255
|
-
|
256
|
+
Aspera.assert_type(@event_build, Hash){'mgt port: unexpected line: data without header'}
|
256
257
|
# event field
|
257
258
|
@event_build[Regexp.last_match(1)] = Regexp.last_match(2)
|
258
259
|
when MGT_FRAME_SEPARATOR
|
259
|
-
|
260
|
+
Aspera.assert_type(@event_build, Hash){'mgt port: unexpected line: end frame without header'}
|
260
261
|
@last_event = @event_build
|
261
262
|
@event_build = nil
|
262
263
|
return @last_event
|
263
264
|
else Aspera.error_unexpected_value(line){'mgt port'}
|
264
265
|
end
|
265
|
-
return
|
266
|
+
return
|
266
267
|
end
|
267
268
|
end
|
268
269
|
end
|
data/lib/aspera/assert.rb
CHANGED
@@ -1,55 +1,86 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
3
|
module Aspera
|
4
|
-
|
4
|
+
# Generic error in gem
|
5
|
+
class Error < StandardError
|
5
6
|
end
|
6
7
|
|
7
|
-
|
8
|
+
# Error that shall not happen, else it's a bug
|
9
|
+
class InternalError < Error
|
10
|
+
end
|
11
|
+
|
12
|
+
# An expected condition was not met
|
13
|
+
class AssertError < Error
|
8
14
|
end
|
9
15
|
class << self
|
10
|
-
#
|
11
|
-
|
16
|
+
# Replace `raise`, allows sending exception, or just error log, when type is `:error`
|
17
|
+
# @param type [Exception,Symbol] Send to log if symbol, else raise exception
|
18
|
+
# @param message [String] Message for error.
|
19
|
+
def report_error(type, message)
|
20
|
+
if type.is_a?(Symbol)
|
21
|
+
Log.log.send(type, message)
|
22
|
+
else
|
23
|
+
raise type, message
|
24
|
+
end
|
25
|
+
end
|
26
|
+
|
27
|
+
# Assert that a condition is true, else raise exception
|
28
|
+
# @param assertion [Bool] Must be true
|
29
|
+
# @param info [String,nil] Fixed message in case assert fails, else use `block`
|
30
|
+
# @param type [Exception,Symbol] Exception to raise, or Symbol for Log.log
|
31
|
+
# @param block [Proc] Produces a string that desribes the problem for complex messages
|
32
|
+
# The block is executed in the context of the Aspera module
|
33
|
+
def assert(assertion, info = nil, type: AssertError)
|
12
34
|
raise InternalError, 'bad assert: both info and block given' unless info.nil? || !block_given?
|
13
35
|
return if assertion
|
14
36
|
message = 'assertion failed'
|
15
37
|
info = yield if block_given?
|
16
38
|
message = "#{message}: #{info}" if info
|
17
39
|
message = "#{message}: #{caller.find{ |call| !call.start_with?(__FILE__)}}"
|
18
|
-
|
40
|
+
report_error(type, message)
|
19
41
|
end
|
20
42
|
|
21
|
-
#
|
22
|
-
# @param value
|
23
|
-
# @param
|
24
|
-
|
25
|
-
|
43
|
+
# Assert that value has the given type
|
44
|
+
# @param value [Object] The value to check
|
45
|
+
# @param classes [Class, Array] The expected type(s)
|
46
|
+
# @param type [Exception,Symbol] Exception to raise, or Symbol for Log.log
|
47
|
+
# @param block [Proc] Additional description in front of message
|
48
|
+
def assert_type(value, *classes, type: AssertError)
|
49
|
+
assert(classes.any?{ |k| value.is_a?(k)}, type: type){"#{"#{yield}: " if block_given?}expecting #{classes.join(', ')}, but have #{value.inspect}"}
|
26
50
|
end
|
27
51
|
|
28
|
-
#
|
29
|
-
# @param value
|
30
|
-
# @param values accepted values
|
31
|
-
# @param
|
32
|
-
|
33
|
-
|
52
|
+
# Assert that value is one of the given values
|
53
|
+
# @param value [any] value to check
|
54
|
+
# @param values [Array] accepted values
|
55
|
+
# @param type [Exception,Symbol] Exception to raise, or Symbol for Log.log
|
56
|
+
# @param block [Proc] Additional description in front of message
|
57
|
+
def assert_values(value, values, type: AssertError)
|
58
|
+
assert(values.include?(value), type: type) do
|
34
59
|
val_list = values.inspect
|
35
60
|
val_list = "one of #{val_list}" if values.is_a?(Array)
|
36
61
|
"#{"#{yield}: " if block_given?}expecting #{val_list}, but have #{value.inspect}"
|
37
62
|
end
|
38
63
|
end
|
39
64
|
|
40
|
-
#
|
65
|
+
# The value is not one of the expected values
|
66
|
+
# @param value [any] The wrong value
|
67
|
+
# @param type [Exception,Symbol] Exception to raise, or Symbol for Log.log
|
68
|
+
# @param block [Proc] Additional description in front of message
|
69
|
+
def error_unexpected_value(value, type: InternalError)
|
70
|
+
report_error(type, "#{"#{yield}: " if block_given?}unexpected value: #{value.inspect}")
|
71
|
+
end
|
72
|
+
|
73
|
+
# The line with this shall never be reached
|
41
74
|
def error_unreachable_line
|
42
75
|
raise InternalError, "unreachable line reached: #{caller(2..2).first}"
|
43
76
|
end
|
44
77
|
|
45
|
-
#
|
46
|
-
|
47
|
-
|
48
|
-
# @param block additional description in front
|
49
|
-
def error_unexpected_value(value, exception_class: InternalError)
|
50
|
-
raise exception_class, "#{"#{yield}: " if block_given?}unexpected value: #{value.inspect}"
|
78
|
+
# Not implemented error
|
79
|
+
def error_not_implemented
|
80
|
+
raise Error, 'Feature not yet implemented'
|
51
81
|
end
|
52
82
|
|
83
|
+
# Use in superclass to require the given method in subclass.
|
53
84
|
def require_method!(name)
|
54
85
|
define_method(name) do |*_args|
|
55
86
|
raise NotImplementedError, "#{self.class} must implement the #{name} method"
|
@@ -9,20 +9,20 @@ module Aspera
|
|
9
9
|
class BasicAuthPlugin < Cli::Plugin
|
10
10
|
class << self
|
11
11
|
def declare_options(options)
|
12
|
-
options.declare(:url, 'URL of application, e.g. https://
|
13
|
-
options.declare(:username, "User's
|
12
|
+
options.declare(:url, 'URL of application, e.g. https://app.example.com/aspera/app')
|
13
|
+
options.declare(:username, "User's identifier")
|
14
14
|
options.declare(:password, "User's password")
|
15
15
|
options.parse_options!
|
16
16
|
end
|
17
17
|
end
|
18
18
|
|
19
|
-
def initialize(basic_options: true
|
20
|
-
super(
|
19
|
+
def initialize(context:, basic_options: true)
|
20
|
+
super(context: context)
|
21
21
|
BasicAuthPlugin.declare_options(options) if basic_options
|
22
22
|
end
|
23
23
|
|
24
24
|
# returns a Rest object with basic auth
|
25
|
-
def basic_auth_params(subpath=nil)
|
25
|
+
def basic_auth_params(subpath = nil)
|
26
26
|
api_url = options.get_option(:url, mandatory: true)
|
27
27
|
api_url = "#{api_url}/#{subpath}" unless subpath.nil?
|
28
28
|
return {
|
@@ -31,10 +31,11 @@ module Aspera
|
|
31
31
|
type: :basic,
|
32
32
|
username: options.get_option(:username, mandatory: true),
|
33
33
|
password: options.get_option(:password, mandatory: true)
|
34
|
-
}
|
34
|
+
}
|
35
|
+
}
|
35
36
|
end
|
36
37
|
|
37
|
-
def basic_auth_api(subpath=nil)
|
38
|
+
def basic_auth_api(subpath = nil)
|
38
39
|
return Rest.new(**basic_auth_params(subpath))
|
39
40
|
end
|
40
41
|
end
|
data/lib/aspera/cli/error.rb
CHANGED
@@ -41,12 +41,12 @@ module Aspera
|
|
41
41
|
hash_array.push(col_titles.zip(values).to_h)
|
42
42
|
end
|
43
43
|
end
|
44
|
-
Log.log.warn('Titled CSV file without any
|
44
|
+
Log.log.warn('Titled CSV file without any row') if hash_array.empty?
|
45
45
|
return hash_array
|
46
46
|
end
|
47
47
|
|
48
|
-
def assert_no_value(
|
49
|
-
raise "no value allowed for extended value type: #{what}" unless
|
48
|
+
def assert_no_value(value, what)
|
49
|
+
raise "no value allowed for extended value type: #{what}" unless value.empty?
|
50
50
|
end
|
51
51
|
end
|
52
52
|
|
@@ -56,25 +56,25 @@ module Aspera
|
|
56
56
|
# base handlers
|
57
57
|
# other handlers can be set using set_handler, e.g. `preset` is reader in config plugin
|
58
58
|
@handlers = {
|
59
|
-
val: lambda{ |
|
60
|
-
base64: lambda{ |
|
61
|
-
csvt: lambda{ |
|
62
|
-
env: lambda{ |
|
63
|
-
file: lambda{ |
|
64
|
-
uri: lambda{ |
|
65
|
-
json: lambda{ |
|
66
|
-
lines: lambda{ |
|
67
|
-
list: lambda{ |
|
68
|
-
none: lambda{ |
|
69
|
-
path: lambda{ |
|
70
|
-
re: lambda{ |
|
71
|
-
ruby: lambda{ |
|
72
|
-
secret: lambda{ |
|
73
|
-
stdin: lambda{ |
|
74
|
-
stdbin: lambda{ |
|
75
|
-
yaml: lambda{ |
|
76
|
-
zlib: lambda{ |
|
77
|
-
extend: lambda{ |
|
59
|
+
val: lambda{ |i| i},
|
60
|
+
base64: lambda{ |i| Base64.decode64(i)},
|
61
|
+
csvt: lambda{ |i| ExtendedValue.decode_csvt(i)},
|
62
|
+
env: lambda{ |i| ENV.fetch(i, nil)},
|
63
|
+
file: lambda{ |i| File.read(File.expand_path(i))},
|
64
|
+
uri: lambda{ |i| UriReader.read(i)},
|
65
|
+
json: lambda{ |i| JSON_parse(i)},
|
66
|
+
lines: lambda{ |i| i.split("\n")},
|
67
|
+
list: lambda{ |i| i[1..-1].split(i[0])},
|
68
|
+
none: lambda{ |i| ExtendedValue.assert_no_value(i, :none); nil}, # rubocop:disable Style/Semicolon
|
69
|
+
path: lambda{ |i| File.expand_path(i)},
|
70
|
+
re: lambda{ |i| Regexp.new(i, Regexp::MULTILINE)},
|
71
|
+
ruby: lambda{ |i| Environment.secure_eval(i, __FILE__, __LINE__)},
|
72
|
+
secret: lambda{ |i| prompt = i.empty? ? 'secret' : i; $stdin.getpass("#{prompt}> ")}, # rubocop:disable Style/Semicolon
|
73
|
+
stdin: lambda{ |i| ExtendedValue.assert_no_value(i, :stdin); $stdin.read}, # rubocop:disable Style/Semicolon
|
74
|
+
stdbin: lambda{ |i| ExtendedValue.assert_no_value(i, :stdbin); $stdin.binmode.read}, # rubocop:disable Style/Semicolon
|
75
|
+
yaml: lambda{ |i| YAML.load(i)},
|
76
|
+
zlib: lambda{ |i| Zlib::Inflate.inflate(i)},
|
77
|
+
extend: lambda{ |i| ExtendedValue.instance.evaluate_all(i)}
|
78
78
|
}
|
79
79
|
@default_decoder = nil
|
80
80
|
end
|
@@ -85,14 +85,15 @@ module Aspera
|
|
85
85
|
end
|
86
86
|
|
87
87
|
# JSON Parser, with more information on error location
|
88
|
-
|
89
|
-
|
88
|
+
# :reek:UncommunicativeMethodName
|
89
|
+
def JSON_parse(value) # rubocop:disable Naming/MethodName
|
90
|
+
JSON.parse(value)
|
90
91
|
rescue JSON::ParserError => e
|
91
92
|
m = /at line (\d+) column (\d+)/.match(e.message)
|
92
93
|
raise if m.nil?
|
93
94
|
line = m[1].to_i - 1
|
94
95
|
column = m[2].to_i - 1
|
95
|
-
lines =
|
96
|
+
lines = value.lines
|
96
97
|
raise if line >= lines.size
|
97
98
|
error_line = lines[line].chomp
|
98
99
|
context_col_beg = [column - 10, 0].max
|
@@ -145,9 +146,7 @@ module Aspera
|
|
145
146
|
# parse string value as extended value
|
146
147
|
# use default decoder if none is specified
|
147
148
|
def evaluate_with_default(value)
|
148
|
-
if value.is_a?(String) && value.match(/^#{handler_regex_string}.*$/).nil? && !@default_decoder.nil?
|
149
|
-
value = [MARKER_START, @default_decoder, MARKER_END, value].join
|
150
|
-
end
|
149
|
+
value = [MARKER_START, @default_decoder, MARKER_END, value].join if value.is_a?(String) && value.match(/^#{handler_regex_string}.*$/).nil? && !@default_decoder.nil?
|
151
150
|
return evaluate(value)
|
152
151
|
end
|
153
152
|
|
@@ -157,7 +156,7 @@ module Aspera
|
|
157
156
|
while (m = value.match(regex))
|
158
157
|
sub_value = "@#{m[2]}:#{m[3]}"
|
159
158
|
Log.log.debug{"evaluating #{sub_value}"}
|
160
|
-
value = m[1]
|
159
|
+
value = "#{m[1]}#{evaluate(sub_value)}#{m[4]}"
|
161
160
|
end
|
162
161
|
return value
|
163
162
|
end
|