aspera-cli 4.22.0 → 4.24.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 +405 -364
- data/CONTRIBUTING.md +86 -29
- data/README.md +1856 -961
- 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 +53 -43
- data/lib/aspera/api/cos_node.rb +7 -5
- data/lib/aspera/api/httpgw.rb +23 -22
- data/lib/aspera/api/node.rb +104 -22
- data/lib/aspera/ascmd.rb +35 -21
- data/lib/aspera/ascp/installation.rb +43 -43
- data/lib/aspera/ascp/management.rb +5 -4
- data/lib/aspera/assert.rb +55 -24
- 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 +38 -4
- data/lib/aspera/cli/main.rb +139 -108
- data/lib/aspera/cli/manager.rb +51 -31
- data/lib/aspera/cli/plugin.rb +149 -78
- data/lib/aspera/cli/plugin_factory.rb +2 -2
- data/lib/aspera/cli/plugins/aoc.rb +217 -88
- data/lib/aspera/cli/plugins/ats.rb +15 -13
- data/lib/aspera/cli/plugins/config.rb +105 -227
- 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 +162 -163
- 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 +233 -247
- 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 +29 -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 +55 -58
- data/lib/aspera/cli/transfer_progress.rb +29 -20
- data/lib/aspera/cli/version.rb +1 -1
- data/lib/aspera/cli/wizard.rb +160 -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/data_repository.rb +1 -0
- data/lib/aspera/environment.rb +144 -100
- 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 +70 -20
- data/lib/aspera/nagios.rb +5 -6
- data/lib/aspera/node_simulator.rb +12 -7
- data/lib/aspera/oauth/base.rb +6 -2
- data/lib/aspera/oauth/factory.rb +25 -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 +43 -35
- data/lib/aspera/preview/generator.rb +26 -13
- data/lib/aspera/preview/terminal.rb +10 -7
- data/lib/aspera/preview/utils.rb +11 -9
- data/lib/aspera/products/connect.rb +2 -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 +46 -28
- data/lib/aspera/rest_call_error.rb +1 -1
- data/lib/aspera/rest_error_analyzer.rb +1 -0
- data/lib/aspera/resumer.rb +1 -1
- data/lib/aspera/secret_hider.rb +46 -40
- data/lib/aspera/ssh.rb +14 -4
- 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/{transfer/sync.rb → sync/operations.rb} +145 -68
- data/lib/aspera/temp_file_manager.rb +4 -2
- data/lib/aspera/timer_limiter.rb +7 -5
- 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 -15
- metadata.gz.sig +0 -0
- data/examples/dascli +0 -30
- data/examples/get_proto_file.rb +0 -8
- data/examples/proxy.pac +0 -60
- data/lib/aspera/transfer/convert.rb +0 -29
- data/lib/aspera/transfer/sync_instance.schema.yaml +0 -13
- data/lib/aspera/transfer/sync_session.schema.yaml +0 -79
data/lib/aspera/cli/plugin.rb
CHANGED
@@ -18,7 +18,9 @@ module Aspera
|
|
18
18
|
# special query parameter: max number of pages for list command
|
19
19
|
MAX_PAGES = 'pmax'
|
20
20
|
# special identifier format: look for this name to find where supported
|
21
|
-
REGEX_LOOKUP_ID_BY_FIELD = /^%([^:]+):(.*)
|
21
|
+
REGEX_LOOKUP_ID_BY_FIELD = /^%([^:]+):(.*)$/
|
22
|
+
PER_PAGE_DEFAULT = 1000
|
23
|
+
private_constant :PER_PAGE_DEFAULT
|
22
24
|
|
23
25
|
class << self
|
24
26
|
def declare_generic_options(options)
|
@@ -29,20 +31,23 @@ module Aspera
|
|
29
31
|
end
|
30
32
|
end
|
31
33
|
|
32
|
-
def
|
33
|
-
def transfer; @broker.transfer; end
|
34
|
-
def config; @broker.config; end
|
35
|
-
def formatter; @broker.formatter; end
|
36
|
-
def persistency; @broker.persistency; end
|
37
|
-
|
38
|
-
def initialize(broker:, man_header: true)
|
34
|
+
def initialize(context:)
|
39
35
|
# check presence in descendant of mandatory method and constant
|
40
|
-
Aspera.assert(respond_to?(:execute_action)){"Missing method 'execute_action' in #{self.class}"}
|
41
|
-
Aspera.assert(self.class.constants.include?(:ACTIONS)){"Missing constant 'ACTIONS' in #{self.class}"}
|
42
|
-
@
|
43
|
-
add_manual_header if man_header
|
36
|
+
Aspera.assert(respond_to?(:execute_action), type: InternalError){"Missing method 'execute_action' in #{self.class}"}
|
37
|
+
Aspera.assert(self.class.constants.include?(:ACTIONS), type: InternalError){"Missing constant 'ACTIONS' in #{self.class}"}
|
38
|
+
@context = context
|
39
|
+
add_manual_header if @context.man_header
|
44
40
|
end
|
45
41
|
|
42
|
+
# Global objects
|
43
|
+
attr_reader :context
|
44
|
+
|
45
|
+
def options; @context.options; end
|
46
|
+
def transfer; @context.transfer; end
|
47
|
+
def config; @context.config; end
|
48
|
+
def formatter; @context.formatter; end
|
49
|
+
def persistency; @context.persistency; end
|
50
|
+
|
46
51
|
def add_manual_header(has_options = true)
|
47
52
|
# manual header for all plugins
|
48
53
|
options.parser.separator('')
|
@@ -51,16 +56,13 @@ module Aspera
|
|
51
56
|
options.parser.separator('OPTIONS:') if has_options
|
52
57
|
end
|
53
58
|
|
54
|
-
#
|
55
|
-
|
56
|
-
|
57
|
-
end
|
58
|
-
|
59
|
-
# must be called AFTER the instance action, ... folder browse <call instance_identifier>
|
59
|
+
# Must be called AFTER the instance action:
|
60
|
+
# ... folder browse _call_instance_identifier
|
61
|
+
#
|
60
62
|
# @param description [String] description of the identifier
|
61
|
-
# @param as_option
|
62
|
-
# @param block
|
63
|
-
# @return
|
63
|
+
# @param as_option [Symbol] option name to use if identifier is an option
|
64
|
+
# @param block [Proc] block to search for identifier based on attribute value
|
65
|
+
# @return [String, Array] identifier or list of ids
|
64
66
|
def instance_identifier(description: 'identifier', as_option: nil, &block)
|
65
67
|
if as_option.nil?
|
66
68
|
res_id = options.get_next_argument(description, multiple: options.get_option(:bulk)) if res_id.nil?
|
@@ -79,24 +81,25 @@ module Aspera
|
|
79
81
|
end
|
80
82
|
|
81
83
|
# For create and delete operations: execute one actin or multiple if bulk is yes
|
82
|
-
# @param command
|
83
|
-
# @param descr
|
84
|
-
# @param values
|
84
|
+
# @param command [Symbol] operation: :create, :delete, ...
|
85
|
+
# @param descr [String] description of the value
|
86
|
+
# @param values [Object] the value(s), or the type of value to get from user
|
85
87
|
# @param id_result [String] key in result hash to use as identifier
|
86
|
-
# @param fields
|
87
|
-
|
88
|
+
# @param fields [Array] fields to display
|
89
|
+
# @param &block [Proc] block to execute for each value
|
90
|
+
def do_bulk_operation(command:, descr: nil, values: Hash, id_result: 'id', fields: :default)
|
88
91
|
Aspera.assert(block_given?){'missing block'}
|
89
92
|
is_bulk = options.get_option(:bulk)
|
90
93
|
case values
|
91
94
|
when :identifier
|
92
|
-
values = instance_identifier
|
95
|
+
values = instance_identifier(description: descr)
|
93
96
|
when Class
|
94
|
-
values = value_create_modify(command: command, type: values, bulk: is_bulk)
|
97
|
+
values = value_create_modify(command: command, description: descr, type: values, bulk: is_bulk)
|
95
98
|
end
|
96
99
|
# if not bulk, there is a single value
|
97
100
|
params = is_bulk ? values : [values]
|
98
101
|
Log.log.warn('Empty list given for bulk operation') if params.empty?
|
99
|
-
Log.
|
102
|
+
Log.dump(:bulk_operation, params)
|
100
103
|
result_list = []
|
101
104
|
params.each do |param|
|
102
105
|
# init for delete
|
@@ -125,78 +128,86 @@ module Aspera
|
|
125
128
|
end
|
126
129
|
end
|
127
130
|
|
128
|
-
#
|
129
|
-
# @param
|
130
|
-
# @param
|
131
|
-
# @param
|
132
|
-
# @param
|
133
|
-
# @param
|
134
|
-
# @param
|
135
|
-
# @param
|
136
|
-
# @param
|
131
|
+
# Operations: Create, Delete, Show, List, Modify
|
132
|
+
# @param api [Rest] api to use
|
133
|
+
# @param entity [String] sub path in URL to resource relative to base url
|
134
|
+
# @param command [Symbol] command to execute: create show list modify delete
|
135
|
+
# @param display_fields [Array] fields to display by default
|
136
|
+
# @param items_key [String] result is in a sub key of the json
|
137
|
+
# @param delete_style [String] if set, the delete operation by array in payload
|
138
|
+
# @param id_as_arg [String] if set, the id is provided as url argument ?<id_as_arg>=<id>
|
139
|
+
# @param is_singleton [Boolean] if true, entity is the full path to the resource
|
140
|
+
# @param tclo [Bool] if set, :list use paging with total_count, limit, offset
|
141
|
+
# @param block [Proc] block to search for identifier based on attribute value
|
137
142
|
# @return result suitable for CLI result
|
138
|
-
def
|
143
|
+
def entity_execute(
|
144
|
+
api:,
|
145
|
+
entity:,
|
146
|
+
command: nil,
|
139
147
|
display_fields: nil,
|
140
|
-
|
148
|
+
items_key: nil,
|
149
|
+
delete_style: nil,
|
141
150
|
id_as_arg: false,
|
142
151
|
is_singleton: false,
|
143
|
-
|
144
|
-
|
152
|
+
list_query: nil,
|
153
|
+
tclo: false,
|
154
|
+
&block
|
155
|
+
)
|
156
|
+
command = options.get_next_command(ALL_OPS) if command.nil?
|
145
157
|
if is_singleton
|
146
|
-
one_res_path =
|
158
|
+
one_res_path = entity
|
147
159
|
elsif INSTANCE_OPS.include?(command)
|
148
160
|
one_res_id = instance_identifier(&block)
|
149
|
-
one_res_path = "#{
|
150
|
-
one_res_path = "#{
|
161
|
+
one_res_path = "#{entity}/#{one_res_id}"
|
162
|
+
one_res_path = "#{entity}?#{id_as_arg}=#{one_res_id}" if id_as_arg
|
151
163
|
end
|
152
164
|
|
153
165
|
case command
|
154
166
|
when :create
|
155
|
-
raise 'cannot create singleton' if is_singleton
|
167
|
+
raise BadArgument, 'cannot create singleton' if is_singleton
|
156
168
|
return do_bulk_operation(command: command, descr: 'data', fields: display_fields) do |params|
|
157
|
-
|
169
|
+
api.create(entity, params)
|
158
170
|
end
|
159
171
|
when :delete
|
160
|
-
raise 'cannot delete singleton' if is_singleton
|
172
|
+
raise BadArgument, 'cannot delete singleton' if is_singleton
|
161
173
|
if !delete_style.nil?
|
162
174
|
one_res_id = [one_res_id] unless one_res_id.is_a?(Array)
|
163
|
-
Aspera.assert_type(one_res_id, Array,
|
164
|
-
|
175
|
+
Aspera.assert_type(one_res_id, Array, type: Cli::BadArgument)
|
176
|
+
api.call(
|
165
177
|
operation: 'DELETE',
|
166
|
-
subpath:
|
178
|
+
subpath: entity,
|
167
179
|
content_type: Rest::MIME_JSON,
|
168
180
|
body: {delete_style => one_res_id},
|
169
181
|
headers: {'Accept' => Rest::MIME_JSON}
|
170
182
|
)
|
171
183
|
return Main.result_status('deleted')
|
172
184
|
end
|
173
|
-
return do_bulk_operation(command: command,
|
174
|
-
|
185
|
+
return do_bulk_operation(command: command, values: one_res_id) do |one_id|
|
186
|
+
api.delete("#{entity}/#{one_id}", query_read_delete)
|
175
187
|
{'id' => one_id}
|
176
188
|
end
|
177
189
|
when :show
|
178
|
-
return Main.result_single_object(
|
190
|
+
return Main.result_single_object(api.read(one_res_path), fields: display_fields)
|
179
191
|
when :list
|
180
|
-
|
192
|
+
if tclo
|
193
|
+
data, total = list_entities_limit_offset_total_count(api: api, entity:, items_key: items_key, query: list_query)
|
194
|
+
return Main.result_object_list(data, total: total, fields: display_fields)
|
195
|
+
end
|
196
|
+
resp = api.call(operation: 'GET', subpath: entity, headers: {'Accept' => Rest::MIME_JSON}, query: query_read_delete)
|
181
197
|
return Main.result_empty if resp[:http].code == '204'
|
182
198
|
data = resp[:data]
|
183
199
|
# TODO: not generic : which application is this for ?
|
184
200
|
if resp[:http]['Content-Type'].start_with?('application/vnd.api+json')
|
185
|
-
Log.log.debug
|
186
|
-
data = data[
|
187
|
-
end
|
188
|
-
if item_list_key
|
189
|
-
item_list = data[item_list_key]
|
190
|
-
total_count = data['total_count']
|
191
|
-
formatter.display_item_count(item_list.length, total_count) unless total_count.nil?
|
192
|
-
data = item_list
|
201
|
+
Log.log.debug('is vnd.api')
|
202
|
+
data = data[entity]
|
193
203
|
end
|
204
|
+
data = data[items_key] if items_key
|
194
205
|
case data
|
195
206
|
when Hash
|
196
207
|
return Main.result_single_object(data, fields: display_fields)
|
197
208
|
when Array
|
198
209
|
return Main.result_object_list(data, fields: display_fields) if data.empty? || data.first.is_a?(Hash)
|
199
|
-
return Main.result_value_list(data
|
210
|
+
return Main.result_value_list(data)
|
200
211
|
else
|
201
212
|
raise "An error occurred: unexpected result type for list: #{data.class}"
|
202
213
|
end
|
@@ -204,21 +215,14 @@ module Aspera
|
|
204
215
|
parameters = value_create_modify(command: command)
|
205
216
|
property = options.get_option(:property)
|
206
217
|
parameters = {property => parameters} unless property.nil?
|
207
|
-
|
218
|
+
api.update(one_res_path, parameters)
|
208
219
|
return Main.result_status('modified')
|
209
220
|
else
|
210
221
|
raise "unknown action: #{command}"
|
211
222
|
end
|
212
223
|
end
|
213
224
|
|
214
|
-
#
|
215
|
-
def entity_action(rest_api, res_class_path, **opts, &block)
|
216
|
-
# res_name=res_class_path.gsub(%r{^.*/},'').gsub(%r{s$},'').gsub('_',' ')
|
217
|
-
command = options.get_next_command(ALL_OPS)
|
218
|
-
return entity_command(command, rest_api, res_class_path, **opts, &block)
|
219
|
-
end
|
220
|
-
|
221
|
-
# query parameters in URL suitable for REST: list/GET and delete/DELETE
|
225
|
+
# Query parameters in URL suitable for REST: list/GET and delete/DELETE
|
222
226
|
def query_read_delete(default: nil)
|
223
227
|
query = options.get_option(:query)
|
224
228
|
# dup default, as it could be frozen
|
@@ -240,23 +244,90 @@ module Aspera
|
|
240
244
|
# @param default [Object] default value if not provided
|
241
245
|
def value_create_modify(command:, description: nil, type: Hash, bulk: false, default: nil)
|
242
246
|
value = options.get_next_argument(
|
243
|
-
"parameters for #{command}#{
|
244
|
-
validation: bulk ? Array : type
|
247
|
+
"parameters for #{command}#{" (#{description})" unless description.nil?}", mandatory: default.nil?,
|
248
|
+
validation: bulk ? Array : type
|
249
|
+
)
|
245
250
|
value = default if value.nil?
|
246
251
|
unless type.nil?
|
247
252
|
type = [type] unless type.is_a?(Array)
|
248
253
|
Aspera.assert(type.all?(Class)){"check types must be a Class, not #{type.map(&:class).join(',')}"}
|
249
254
|
if bulk
|
250
|
-
Aspera.assert_type(value, Array,
|
255
|
+
Aspera.assert_type(value, Array, type: Cli::BadArgument)
|
251
256
|
value.each do |v|
|
252
|
-
Aspera.assert_values(v.class, type,
|
257
|
+
Aspera.assert_values(v.class, type, type: Cli::BadArgument)
|
253
258
|
end
|
254
259
|
else
|
255
|
-
Aspera.assert_values(value.class, type,
|
260
|
+
Aspera.assert_values(value.class, type, type: Cli::BadArgument)
|
256
261
|
end
|
257
262
|
end
|
258
263
|
return value
|
259
264
|
end
|
265
|
+
|
266
|
+
# Get a (full or partial) list of all entities of a given type with query: offset/limit
|
267
|
+
# @param `api` [Rest] the API object
|
268
|
+
# @param `entity` [String,Symbol] the API endpoint of entity to list
|
269
|
+
# @param `items_key` [String] key in the result to get the list of items
|
270
|
+
# @param `query` [Hash,nil] additional query parameters
|
271
|
+
# @return [Array] items, total_count
|
272
|
+
def list_entities_limit_offset_total_count(
|
273
|
+
api:,
|
274
|
+
entity:,
|
275
|
+
items_key: nil,
|
276
|
+
query: nil
|
277
|
+
)
|
278
|
+
entity = entity.to_s if entity.is_a?(Symbol)
|
279
|
+
items_key = entity.split('/').last if items_key.nil?
|
280
|
+
query = {} if query.nil?
|
281
|
+
Aspera.assert_type(entity, String)
|
282
|
+
Aspera.assert_type(items_key, String)
|
283
|
+
Aspera.assert_type(query, Hash)
|
284
|
+
Log.log.debug{"list_entities t=#{entity} k=#{items_key} q=#{query}"}
|
285
|
+
result = []
|
286
|
+
offset = 0
|
287
|
+
max_items = query.delete(MAX_ITEMS)
|
288
|
+
remain_pages = query.delete(MAX_PAGES)
|
289
|
+
# merge default parameters, by default 100 per page
|
290
|
+
query = {'limit'=> PER_PAGE_DEFAULT}.merge(query)
|
291
|
+
total_count = nil
|
292
|
+
loop do
|
293
|
+
query['offset'] = offset
|
294
|
+
page_result = api.read(entity, query)
|
295
|
+
Aspera.assert_type(page_result[items_key], Array)
|
296
|
+
result.concat(page_result[items_key])
|
297
|
+
# reach the limit set by user ?
|
298
|
+
if !max_items.nil? && (result.length >= max_items)
|
299
|
+
result = result.slice(0, max_items)
|
300
|
+
break
|
301
|
+
end
|
302
|
+
total_count ||= page_result['total_count']
|
303
|
+
break if result.length >= total_count
|
304
|
+
remain_pages -= 1 unless remain_pages.nil?
|
305
|
+
break if remain_pages == 0
|
306
|
+
offset += page_result[items_key].length
|
307
|
+
formatter.long_operation_running
|
308
|
+
end
|
309
|
+
formatter.long_operation_terminated
|
310
|
+
return result, total_count
|
311
|
+
end
|
312
|
+
|
313
|
+
# Lookup an entity id from its name
|
314
|
+
# @param entity [String] the type of entity to lookup, by default it is the path, and it is also the field name in result
|
315
|
+
# @param value [String] the value to lookup
|
316
|
+
# @param field [String] the field to match, by default it is 'name'
|
317
|
+
# @param items_key [String] key in the result to get the list of items (override entity)
|
318
|
+
# @param query [Hash] additional query parameters
|
319
|
+
def lookup_entity_by_field(api:, entity:, value:, field: 'name', items_key: nil, query: :default)
|
320
|
+
if query.eql?(:default)
|
321
|
+
Aspera.assert(field.eql?('name')){'Default query is on name only'}
|
322
|
+
query = {'q'=> value}
|
323
|
+
end
|
324
|
+
found = list_entities_limit_offset_total_count(api: api, entity: entity, items_key: items_key, query: query).first.select{ |i| i[field].eql?(value)}
|
325
|
+
case found.length
|
326
|
+
when 0 then raise "No #{entity} with #{field} = #{value}"
|
327
|
+
when 1 then return found.first
|
328
|
+
else raise "Found #{found.length} #{entity} with #{field} = #{value}"
|
329
|
+
end
|
330
|
+
end
|
260
331
|
end
|
261
332
|
end
|
262
333
|
end
|
@@ -48,7 +48,7 @@ module Aspera
|
|
48
48
|
|
49
49
|
# @return Class object for plugin
|
50
50
|
def plugin_class(plugin_name_sym)
|
51
|
-
raise "
|
51
|
+
raise NoSuchElement, "plugin not found: #{plugin_name_sym}" unless @plugins.key?(plugin_name_sym)
|
52
52
|
require @plugins[plugin_name_sym][:require_stanza]
|
53
53
|
# Module.nesting[1] is Aspera::Cli
|
54
54
|
return Object.const_get("#{Module.nesting[1]}::#{PLUGINS_MODULE}::#{plugin_name_sym.to_s.capitalize}")
|
@@ -67,7 +67,7 @@ module Aspera
|
|
67
67
|
# add plugin information to list
|
68
68
|
# @param path [String] path to plugin source file
|
69
69
|
def add_plugin_info(path)
|
70
|
-
raise "
|
70
|
+
raise Error, "plugin path must end with #{RUBY_FILE_EXT}" if !path.end_with?(RUBY_FILE_EXT)
|
71
71
|
plugin_symbol = File.basename(path, RUBY_FILE_EXT).to_sym
|
72
72
|
req = path.sub(/#{RUBY_FILE_EXT}$/o, '')
|
73
73
|
if @plugins.key?(plugin_symbol)
|