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/cli/plugin.rb
CHANGED
@@ -16,67 +16,77 @@ module Aspera
|
|
16
16
|
MAX_ITEMS = 'max'
|
17
17
|
# special query parameter: max number of pages for list command
|
18
18
|
MAX_PAGES = 'pmax'
|
19
|
-
# used when all resources are selected
|
20
|
-
VAL_ALL = 'ALL'
|
21
19
|
# special identifier format: look for this name to find where supported
|
22
20
|
REGEX_LOOKUP_ID_BY_FIELD = /^%([^:]+):(.*)$/.freeze
|
23
21
|
|
24
|
-
|
25
|
-
|
22
|
+
class << self
|
23
|
+
def declare_generic_options(options)
|
24
|
+
options.declare(:query, 'Additional filter for for some commands (list/delete)', types: Hash)
|
25
|
+
options.declare(
|
26
|
+
:value, 'Value for create, update, list filter', types: Hash,
|
27
|
+
deprecation: '(4.14) Use positional value for create/modify or option: query for list/delete')
|
28
|
+
options.declare(:property, 'Name of property to set (modify operation)')
|
29
|
+
options.declare(:id, 'Resource identifier', deprecation: "(4.14) Use positional identifier after verb (#{INSTANCE_OPS.join(',')})")
|
30
|
+
options.declare(:bulk, 'Bulk operation (only some)', values: :bool, default: :no)
|
31
|
+
options.declare(:bfail, 'Bulk operation error handling', values: :bool, default: :yes)
|
32
|
+
end
|
33
|
+
end
|
26
34
|
|
27
35
|
def initialize(env)
|
28
|
-
raise 'must be Hash' unless env.is_a?(Hash)
|
29
|
-
# env.each_key {|k| raise "wrong agent key #{k}" unless AGENTS.include?(k)}
|
36
|
+
raise 'env must be Hash' unless env.is_a?(Hash)
|
30
37
|
@agents = env
|
31
38
|
# check presence in descendant of mandatory method and constant
|
32
39
|
raise StandardError, "Missing method 'execute_action' in #{self.class}" unless respond_to?(:execute_action)
|
33
40
|
raise StandardError, 'ACTIONS shall be redefined by subclass' unless self.class.constants.include?(:ACTIONS)
|
41
|
+
# manual header for all plugins
|
34
42
|
options.parser.separator('')
|
35
43
|
options.parser.separator("COMMAND: #{self.class.name.split('::').last.downcase}")
|
36
44
|
options.parser.separator("SUBCOMMANDS: #{self.class.const_get(:ACTIONS).map(&:to_s).sort.join(' ')}")
|
37
45
|
options.parser.separator('OPTIONS:')
|
38
|
-
return if @@options_created
|
39
|
-
options.declare(:query, 'Additional filter for for some commands (list/delete)', types: Hash)
|
40
|
-
options.declare(
|
41
|
-
:value, 'Value for create, update, list filter', types: Hash,
|
42
|
-
deprecation: 'Use positional value for create/modify or option: query for list/delete')
|
43
|
-
options.declare(:property, 'Name of property to set (modify operation)')
|
44
|
-
options.declare(:id, 'Resource identifier', deprecation: "Use identifier after verb (#{INSTANCE_OPS.join(',')})")
|
45
|
-
options.declare(:bulk, 'Bulk operation (only some)', values: :bool, default: :no)
|
46
|
-
options.declare(:bfail, 'Bulk operation error handling', values: :bool, default: :yes)
|
47
|
-
options.parse_options!
|
48
|
-
@@options_created = true # rubocop:disable Style/ClassVars
|
49
46
|
end
|
50
47
|
|
51
48
|
# must be called AFTER the instance action, ... folder browse <call instance_identifier>
|
52
49
|
# @param description [String] description of the identifier
|
50
|
+
# @param as_option [Symbol] option name to use if identifier is an option
|
53
51
|
# @param block [Proc] block to search for identifier based on attribute value
|
54
52
|
# @return [String] identifier
|
55
|
-
def instance_identifier(description: 'identifier', &block)
|
56
|
-
|
57
|
-
|
53
|
+
def instance_identifier(description: 'identifier', as_option: nil, &block)
|
54
|
+
if as_option.nil?
|
55
|
+
res_id = options.get_option(:id)
|
56
|
+
res_id = options.get_next_argument(description) if res_id.nil?
|
57
|
+
else
|
58
|
+
res_id = options.get_option(as_option)
|
59
|
+
end
|
58
60
|
# cab be an Array
|
59
61
|
if res_id.is_a?(String) && (m = res_id.match(REGEX_LOOKUP_ID_BY_FIELD))
|
60
62
|
if block
|
61
63
|
res_id = yield(m[1], ExtendedValue.instance.evaluate(m[2]))
|
62
64
|
else
|
63
|
-
raise
|
65
|
+
raise Cli::BadArgument, "Percent syntax for #{description} not supported in this context"
|
64
66
|
end
|
65
67
|
end
|
66
68
|
return res_id
|
67
69
|
end
|
68
70
|
|
69
71
|
# For create and delete operations: execute one actin or multiple if bulk is yes
|
70
|
-
# @param
|
71
|
-
# @param
|
72
|
+
# @param command [Symbol] operation: :create, :delete, ...
|
73
|
+
# @param descr [String] description of the value
|
74
|
+
# @param values [Object] the value(s), or the type of value to get from user
|
72
75
|
# @param id_result [String] key in result hash to use as identifier
|
73
76
|
# @param fields [Array] fields to display
|
74
|
-
def do_bulk_operation(
|
75
|
-
|
76
|
-
|
77
|
-
|
77
|
+
def do_bulk_operation(command:, descr:, values: Hash, id_result: 'id', fields: :default)
|
78
|
+
is_bulk = options.get_option(:bulk)
|
79
|
+
case values
|
80
|
+
when :identifier
|
81
|
+
values = instance_identifier
|
82
|
+
when Class
|
83
|
+
values = value_create_modify(command: command, type: values, bulk: is_bulk)
|
84
|
+
end
|
85
|
+
raise 'Internal error: missing block' unless block_given?
|
86
|
+
# if not bulk, there is a single value
|
87
|
+
params = is_bulk ? values : [values]
|
78
88
|
Log.log.warn('Empty list given for bulk operation') if params.empty?
|
79
|
-
Log.dump(:bulk_operation, params)
|
89
|
+
Log.log.debug{Log.dump(:bulk_operation, params)}
|
80
90
|
result_list = []
|
81
91
|
params.each do |param|
|
82
92
|
# init for delete
|
@@ -86,7 +96,8 @@ module Aspera
|
|
86
96
|
res = yield(param)
|
87
97
|
# if block returns a hash, let's use this (create)
|
88
98
|
result = res if param.is_a?(Hash)
|
89
|
-
|
99
|
+
# create -> created
|
100
|
+
result['status'] = "#{command}#{'e' unless command.to_s.end_with?('e')}d".gsub(/yed$/, 'ied')
|
90
101
|
rescue StandardError => e
|
91
102
|
raise e if options.get_option(:bfail)
|
92
103
|
result['status'] = e.to_s
|
@@ -94,7 +105,7 @@ module Aspera
|
|
94
105
|
result_list.push(result)
|
95
106
|
end
|
96
107
|
display_fields = [id_result, 'status']
|
97
|
-
if
|
108
|
+
if is_bulk
|
98
109
|
return {type: :object_list, data: result_list, fields: display_fields}
|
99
110
|
else
|
100
111
|
display_fields = fields unless fields.eql?(:default)
|
@@ -106,21 +117,16 @@ module Aspera
|
|
106
117
|
# @param rest_api [Rest] api to use
|
107
118
|
# @param res_class_path [String] sub path in URL to resource relative to base url
|
108
119
|
# @param display_fields [Array] fields to display by default
|
109
|
-
# @param id_default [String] default identifier to use for existing entity commands (show, modify)
|
110
120
|
# @param item_list_key [String] result is in a sub key of the json
|
111
121
|
# @param id_as_arg [String] if set, the id is provided as url argument ?<id_as_arg>=<id>
|
112
122
|
# @param is_singleton [Boolean] if true, res_class_path is the full path to the resource
|
123
|
+
# @param block [Proc] block to search for identifier based on attribute value
|
113
124
|
# @return result suitable for CLI result
|
114
|
-
def entity_command(command, rest_api, res_class_path, display_fields: nil,
|
125
|
+
def entity_command(command, rest_api, res_class_path, display_fields: nil, item_list_key: false, id_as_arg: false, is_singleton: false, &block)
|
115
126
|
if is_singleton
|
116
127
|
one_res_path = res_class_path
|
117
128
|
elsif INSTANCE_OPS.include?(command)
|
118
|
-
|
119
|
-
one_res_id = instance_identifier(&block)
|
120
|
-
rescue StandardError => e
|
121
|
-
raise e if id_default.nil?
|
122
|
-
one_res_id = id_default
|
123
|
-
end
|
129
|
+
one_res_id = instance_identifier(&block)
|
124
130
|
one_res_path = "#{res_class_path}/#{one_res_id}"
|
125
131
|
one_res_path = "#{res_class_path}?#{id_as_arg}=#{one_res_id}" if id_as_arg
|
126
132
|
end
|
@@ -128,13 +134,12 @@ module Aspera
|
|
128
134
|
case command
|
129
135
|
when :create
|
130
136
|
raise 'cannot create singleton' if is_singleton
|
131
|
-
return do_bulk_operation(
|
132
|
-
raise 'expecting Hash' unless params.is_a?(Hash)
|
137
|
+
return do_bulk_operation(command: command, descr: 'data', fields: display_fields) do |params|
|
133
138
|
rest_api.create(res_class_path, params)[:data]
|
134
139
|
end
|
135
140
|
when :delete
|
136
141
|
raise 'cannot delete singleton' if is_singleton
|
137
|
-
return do_bulk_operation(
|
142
|
+
return do_bulk_operation(command: command, descr: 'identifier', values: one_res_id) do |one_id|
|
138
143
|
rest_api.delete("#{res_class_path}/#{one_id}", old_query_read_delete)
|
139
144
|
{'id' => one_id}
|
140
145
|
end
|
@@ -164,7 +169,7 @@ module Aspera
|
|
164
169
|
raise "An error occurred: unexpected result type for list: #{data.class}"
|
165
170
|
end
|
166
171
|
when :modify
|
167
|
-
parameters = value_create_modify(command: command
|
172
|
+
parameters = value_create_modify(command: command)
|
168
173
|
property = options.get_option(:property)
|
169
174
|
parameters = {property => parameters} unless property.nil?
|
170
175
|
rest_api.update(one_res_path, parameters)
|
@@ -191,12 +196,13 @@ module Aspera
|
|
191
196
|
# check it is suitable
|
192
197
|
URI.encode_www_form(query) unless query.nil?
|
193
198
|
rescue StandardError => e
|
194
|
-
raise
|
199
|
+
raise Cli::BadArgument, "Query must be an extended value which can be encoded with URI.encode_www_form. Refer to manual. (#{e.message})"
|
195
200
|
end
|
196
201
|
return query
|
197
202
|
end
|
198
203
|
|
199
204
|
# TODO: when deprecation of `value` is completed: remove this method, replace with query_read_delete
|
205
|
+
# deprecation: 4.14
|
200
206
|
def old_query_read_delete
|
201
207
|
query = options.get_option(:value) # legacy, deprecated, remove, one day...
|
202
208
|
query = query_read_delete if query.nil?
|
@@ -204,31 +210,36 @@ module Aspera
|
|
204
210
|
end
|
205
211
|
|
206
212
|
# TODO: when deprecation of `value` is completed: remove this method, replace with options.get_option(:query)
|
207
|
-
|
208
|
-
|
209
|
-
|
213
|
+
# deprecation: 4.14
|
214
|
+
def query_option(mandatory: false, default: nil)
|
215
|
+
option = :value
|
216
|
+
value = options.get_option(option, mandatory: false)
|
217
|
+
if value.nil?
|
218
|
+
option = :query
|
219
|
+
value = options.get_option(option, mandatory: mandatory, default: default)
|
220
|
+
end
|
210
221
|
return value
|
211
222
|
end
|
212
223
|
|
213
224
|
# Retrieves an extended value from command line, used for creation or modification of entities
|
225
|
+
# @param command [Symbol] command name for error message
|
226
|
+
# @param type [Class] expected type of value, either a Class, an Array of Class, or :bulk_hash
|
214
227
|
# @param default [Object] default value if not provided
|
215
|
-
# @param command [String] command name for error message
|
216
|
-
# @param type [Class] expected type of value
|
217
228
|
# TODO: when deprecation of `value` is completed: remove line with :value
|
218
|
-
def value_create_modify(
|
229
|
+
def value_create_modify(command:, type: Hash, bulk: false, default: nil)
|
219
230
|
value = options.get_option(:value)
|
231
|
+
Log.log.warn("option `value` is deprecated. Use positional parameter for #{command}") unless value.nil?
|
220
232
|
value = options.get_next_argument("parameters for #{command}", mandatory: default.nil?) if value.nil?
|
221
233
|
value = default if value.nil?
|
222
|
-
|
223
|
-
|
224
|
-
|
225
|
-
|
226
|
-
|
227
|
-
|
228
|
-
|
229
|
-
|
230
|
-
|
231
|
-
raise "Internal error: #{type}"
|
234
|
+
unless type.nil?
|
235
|
+
type = [type] unless type.is_a?(Array)
|
236
|
+
raise "Internal error, check types must be a Class, not #{type.map(&:class).join(',')}" unless type.all?(Class)
|
237
|
+
if bulk
|
238
|
+
raise Cli::BadArgument, "Value must be an Array of #{type.join(',')}" unless value.is_a?(Array)
|
239
|
+
raise Cli::BadArgument, "Value must be a #{type.join(',')}, not #{value.map{|i| i.class.name}.uniq.join(',')}" unless value.all?{|v|type.include?(v.class)}
|
240
|
+
else
|
241
|
+
raise Cli::BadArgument, "Value must be a #{type.join(',')}, not #{value.class.name}" unless type.include?(value.class)
|
242
|
+
end
|
232
243
|
end
|
233
244
|
return value
|
234
245
|
end
|