aspera-cli 4.27.1 → 4.27.3
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 +67 -1
- data/bin/ascli +2 -1
- data/docs/README.md +805 -747
- data/lib/aspera/agent/connect.rb +6 -4
- data/lib/aspera/agent/desktop.rb +2 -2
- data/lib/aspera/agent/direct.rb +3 -1
- data/lib/aspera/agent/node.rb +3 -3
- data/lib/aspera/api/alee.rb +1 -1
- data/lib/aspera/api/aoc.rb +14 -12
- data/lib/aspera/api/ats.rb +1 -1
- data/lib/aspera/api/cos_node.rb +2 -2
- data/lib/aspera/api/faspex.rb +9 -7
- data/lib/aspera/api/httpgw.rb +37 -33
- data/lib/aspera/api/node.rb +38 -33
- data/lib/aspera/ascmd.rb +3 -1
- data/lib/aspera/ascp/installation.rb +62 -27
- data/lib/aspera/ascp/management.rb +1 -0
- data/lib/aspera/assert.rb +4 -0
- data/lib/aspera/cli/ascp_actions.rb +20 -41
- data/lib/aspera/cli/async_transfer_store.rb +2 -2
- data/lib/aspera/cli/bootstrapper.rb +11 -15
- data/lib/aspera/cli/command_line.rb +252 -0
- data/lib/aspera/cli/command_registry.rb +149 -33
- data/lib/aspera/cli/command_spec.rb +103 -14
- data/lib/aspera/cli/completion/ascli.bash +12 -0
- data/lib/aspera/cli/completion/ascli.fish +16 -0
- data/lib/aspera/cli/completion/ascli.zsh +19 -0
- data/lib/aspera/cli/context.rb +3 -0
- data/lib/aspera/cli/deprecation.rb +37 -0
- data/lib/aspera/cli/extended_value.rb +2 -0
- data/lib/aspera/cli/formatter.rb +87 -75
- data/lib/aspera/cli/gem_checker.rb +1 -1
- data/lib/aspera/cli/hints.rb +7 -6
- data/lib/aspera/cli/http.rb +21 -21
- data/lib/aspera/cli/info.rb +3 -0
- data/lib/aspera/cli/mcp_tool.rb +47 -83
- data/lib/aspera/cli/option_declarator.rb +33 -42
- data/lib/aspera/cli/option_registry.rb +69 -0
- data/lib/aspera/cli/option_types.rb +103 -0
- data/lib/aspera/cli/option_value.rb +281 -0
- data/lib/aspera/cli/options.schema.yaml +38 -5
- data/lib/aspera/cli/parser.rb +307 -848
- data/lib/aspera/cli/plugins/alee.rb +7 -4
- data/lib/aspera/cli/plugins/aoc.rb +435 -380
- data/lib/aspera/cli/plugins/ats.rb +58 -73
- data/lib/aspera/cli/plugins/base.rb +190 -240
- data/lib/aspera/cli/plugins/basic_auth.rb +2 -10
- data/lib/aspera/cli/plugins/config.rb +244 -178
- data/lib/aspera/cli/plugins/console.rb +102 -38
- data/lib/aspera/cli/plugins/cos.rb +6 -23
- data/lib/aspera/cli/plugins/factory.rb +3 -0
- data/lib/aspera/cli/plugins/faspex5.rb +176 -173
- data/lib/aspera/cli/plugins/faspio.rb +5 -10
- data/lib/aspera/cli/plugins/httpgw.rb +8 -11
- data/lib/aspera/cli/plugins/mcp.rb +20 -55
- data/lib/aspera/cli/plugins/node.rb +277 -311
- data/lib/aspera/cli/plugins/orchestrator.rb +90 -77
- data/lib/aspera/cli/plugins/preview.rb +79 -90
- data/lib/aspera/cli/plugins/server.rb +76 -50
- data/lib/aspera/cli/plugins/shares.rb +68 -116
- data/lib/aspera/cli/preset_actions.rb +17 -10
- data/lib/aspera/cli/preset_manager.rb +12 -2
- data/lib/aspera/cli/prompt.rb +35 -0
- data/lib/aspera/cli/result.rb +13 -18
- data/lib/aspera/cli/runner.rb +31 -54
- data/lib/aspera/cli/special_values.rb +5 -0
- data/lib/aspera/cli/sync_actions.rb +41 -37
- data/lib/aspera/cli/terminal_formatter.rb +9 -3
- data/lib/aspera/cli/transfer_actions.rb +0 -6
- data/lib/aspera/cli/transfer_agent.rb +29 -35
- data/lib/aspera/cli/vault_manager.rb +0 -17
- data/lib/aspera/cli/version.rb +1 -1
- data/lib/aspera/cli/wizard.rb +4 -2
- data/lib/aspera/command_line_builder.rb +1 -0
- data/lib/aspera/coverage.rb +1 -0
- data/lib/aspera/environment.rb +7 -1
- data/lib/aspera/faspex_gw.rb +2 -1
- data/lib/aspera/faspex_postproc.rb +1 -0
- data/lib/aspera/graphql.rb +5 -5
- data/lib/aspera/json_rpc/client.rb +5 -5
- data/lib/aspera/keychain/encrypted_hash.rb +1 -1
- data/lib/aspera/keychain/one_password_api.rb +1 -1
- data/lib/aspera/link_header.rb +2 -2
- data/lib/aspera/log.rb +22 -25
- data/lib/aspera/markdown.rb +2 -0
- data/lib/aspera/mime.rb +25 -0
- data/lib/aspera/node_simulator.rb +1 -0
- data/lib/aspera/oauth/base.rb +35 -25
- data/lib/aspera/oauth/factory.rb +1 -0
- data/lib/aspera/oauth/generic.rb +1 -1
- data/lib/aspera/oauth/jwt.rb +1 -1
- data/lib/aspera/oauth/web.rb +9 -8
- data/lib/aspera/preview/file_types.rb +4 -4
- data/lib/aspera/preview/generator.rb +7 -0
- data/lib/aspera/preview/options.rb +4 -4
- data/lib/aspera/preview/terminal.rb +4 -3
- data/lib/aspera/preview/utils.rb +9 -6
- data/lib/aspera/products/connect.rb +1 -1
- data/lib/aspera/rainbow.rb +7 -0
- data/lib/aspera/rest/aspera_errors.rb +60 -0
- data/lib/aspera/rest/call_error.rb +27 -0
- data/lib/aspera/rest/client.rb +514 -0
- data/lib/aspera/rest/error_analyzer.rb +113 -0
- data/lib/aspera/rest/list.rb +143 -0
- data/lib/aspera/rest/parameters.rb +55 -0
- data/lib/aspera/rest/util.rb +176 -0
- data/lib/aspera/rest.rb +7 -621
- data/lib/aspera/schema/IBM Aspera Console-enhanced.yaml +1125 -0
- data/lib/aspera/schema/IBM Aspera on Cloud API-0.2.6-enhanced.yaml +39 -0
- data/lib/aspera/schema/IBM Aspera on Cloud Automation API-1.0.5-enhanced.yaml +2395 -0
- data/lib/aspera/schema/documentation.rb +13 -3
- data/lib/aspera/schema/registry.rb +18 -1
- data/lib/aspera/schema/validator.rb +92 -0
- data/lib/aspera/secret_hider.rb +36 -25
- data/lib/aspera/string_ext.rb +15 -0
- data/lib/aspera/temp_file_manager.rb +6 -5
- data/lib/aspera/transfer/parameters.rb +2 -0
- data/lib/aspera/transfer/spec.rb +1 -0
- data/lib/aspera/transfer/spec.schema.yaml +1 -0
- data/lib/aspera/uri_reader.rb +11 -11
- data/lib/aspera/web_auth/index.html +147 -0
- data/lib/aspera/web_auth/server.rb +81 -0
- data.tar.gz.sig +0 -0
- metadata +39 -7
- metadata.gz.sig +0 -0
- data/lib/aspera/colors.rb +0 -79
- data/lib/aspera/rest_call_error.rb +0 -25
- data/lib/aspera/rest_error_analyzer.rb +0 -111
- data/lib/aspera/rest_errors_aspera.rb +0 -58
- data/lib/aspera/rest_list.rb +0 -136
- data/lib/aspera/web_auth.rb +0 -211
|
@@ -22,7 +22,7 @@ module Aspera
|
|
|
22
22
|
error = nil
|
|
23
23
|
urls.each do |base_url|
|
|
24
24
|
next unless base_url.start_with?('https://')
|
|
25
|
-
api = Rest.new(base_url: base_url, redirect_max: 2)
|
|
25
|
+
api = Rest::Client.new(base_url: base_url, redirect_max: 2)
|
|
26
26
|
test_endpoint = 'login'
|
|
27
27
|
http = api.call(
|
|
28
28
|
operation: 'GET',
|
|
@@ -67,27 +67,68 @@ module Aspera
|
|
|
67
67
|
}
|
|
68
68
|
end
|
|
69
69
|
|
|
70
|
-
def initialize(**_)
|
|
71
|
-
super
|
|
72
|
-
end
|
|
73
|
-
|
|
74
70
|
# --- DSL ---
|
|
75
71
|
|
|
76
|
-
command :health, description: 'Check Console API health'
|
|
77
|
-
command :transfer, description: 'Manage transfers'
|
|
72
|
+
command :health, description: 'Check Console API health'
|
|
73
|
+
command :transfer, description: 'Manage transfers'
|
|
74
|
+
command :endpoint, description: 'Manage endpoints'
|
|
75
|
+
command :ssh_key, description: 'Manage SSH keys'
|
|
76
|
+
command :admin, description: 'Administer Console'
|
|
78
77
|
|
|
79
78
|
commands_under :transfer do
|
|
80
79
|
command :current, description: 'Manage current transfers'
|
|
81
80
|
command :smart, description: 'Manage smart transfers'
|
|
81
|
+
command :queue, description: 'Manage transfers of a queue',
|
|
82
|
+
arguments: [{name: :queue_id, type: :identifier}]
|
|
83
|
+
end
|
|
84
|
+
|
|
85
|
+
commands_under :endpoint do
|
|
86
|
+
command :list, description: operation_description(:list, 'endpoint'),
|
|
87
|
+
action: ->(**) { Result::ObjectList.new(api_console.read('endpoints')) }
|
|
88
|
+
end
|
|
89
|
+
|
|
90
|
+
# Payload is not documented in the API: optional
|
|
91
|
+
# command => name of argument
|
|
92
|
+
ADMIN_UPDATES = {email_server_update: :email_server, nodeapi_credentials_update: :credentials}.freeze
|
|
93
|
+
private_constant :ADMIN_UPDATES
|
|
94
|
+
|
|
95
|
+
commands_under :admin do
|
|
96
|
+
command :email_server_update, description: 'Update email server configuration',
|
|
97
|
+
arguments: [{name: ADMIN_UPDATES[:email_server_update], type: Hash, mandatory: false, default: {}}]
|
|
98
|
+
command :nodeapi_credentials_update, description: 'Update Node API credentials',
|
|
99
|
+
arguments: [{name: ADMIN_UPDATES[:nodeapi_credentials_update], type: Hash, mandatory: false, default: {}}]
|
|
100
|
+
end
|
|
101
|
+
|
|
102
|
+
# POST <verb>
|
|
103
|
+
ADMIN_UPDATES.each do |verb, arg|
|
|
104
|
+
define_action_method([:admin, verb]) do |**kwargs|
|
|
105
|
+
api_console.create(verb.to_s, kwargs.fetch(arg))
|
|
106
|
+
Result::Success.new
|
|
107
|
+
end
|
|
108
|
+
end
|
|
109
|
+
|
|
110
|
+
commands_under :ssh_key do
|
|
111
|
+
command :list, description: operation_description(:list, 'SSH key'),
|
|
112
|
+
action: ->(**) { Result::ObjectList.new(api_console.read('ssh_keys')) }
|
|
82
113
|
end
|
|
83
114
|
|
|
84
115
|
commands_under %i[transfer current] do
|
|
85
116
|
command :list, description: 'List current transfers'
|
|
117
|
+
command :submit, description: 'Submit a simple transfer',
|
|
118
|
+
arguments: [{name: :transfer, type: Hash, schema: Schema::Registry.req_body(Schema::Registry::CONSOLE, 'transfers.post')}],
|
|
119
|
+
action: ->(transfer:, **) { Result::SingleObject.new(api_console.create('transfers', transfer)) }
|
|
86
120
|
command :show, description: 'Show a transfer',
|
|
87
121
|
arguments: [{name: :transfer_id, type: :identifier}],
|
|
88
|
-
action: ->(
|
|
89
|
-
command
|
|
90
|
-
|
|
122
|
+
action: ->(transfer_id:, **) { Result::SingleObject.new(api_console.read("transfers/#{transfer_id}")) }
|
|
123
|
+
command(
|
|
124
|
+
:files, description: 'List files in a transfer',
|
|
125
|
+
arguments: [{name: :transfer_id, type: :identifier}],
|
|
126
|
+
action: lambda do |transfer_id:, **|
|
|
127
|
+
query = query_read_delete(default: {})
|
|
128
|
+
query['limit'] ||= 100
|
|
129
|
+
Result::ObjectList.new(api_console.read("transfers/#{transfer_id}/files", query))
|
|
130
|
+
end
|
|
131
|
+
)
|
|
91
132
|
command :start, description: 'Start a transfer',
|
|
92
133
|
arguments: [{name: :transfer_id, type: :identifier}]
|
|
93
134
|
command :pause, description: 'Pause a transfer',
|
|
@@ -97,44 +138,77 @@ module Aspera
|
|
|
97
138
|
command :resume, description: 'Resume a transfer',
|
|
98
139
|
arguments: [{name: :transfer_id, type: :identifier}]
|
|
99
140
|
command :rerun, description: 'Rerun a transfer',
|
|
100
|
-
arguments: [{name: :transfer_id, type: :identifier}]
|
|
141
|
+
arguments: [{name: :transfer_id, type: :identifier}],
|
|
142
|
+
action: ->(transfer_id:, **) { Result::SingleObject.new(api_console.create("transfers/#{transfer_id}/rerun", {})) }
|
|
101
143
|
command :change_rate, description: 'Change transfer rate',
|
|
102
|
-
arguments: [{name: :transfer_id, type: :identifier}
|
|
144
|
+
arguments: [{name: :transfer_id, type: :identifier},
|
|
145
|
+
{name: :rate, type: Hash, schema: Schema::Registry.req_body(Schema::Registry::CONSOLE, 'transfers/{id}/change_rate.put')}]
|
|
103
146
|
command :change_policy, description: 'Change transfer policy',
|
|
147
|
+
arguments: [{name: :transfer_id, type: :identifier},
|
|
148
|
+
{name: :policy, type: Hash, schema: Schema::Registry.req_body(Schema::Registry::CONSOLE, 'transfers/{id}/change_policy.put')}]
|
|
149
|
+
end
|
|
150
|
+
|
|
151
|
+
commands_under %i[transfer queue] do
|
|
152
|
+
command :list, description: 'List transfers in queue, frontmost first',
|
|
153
|
+
action: ->(queue_id:, **) { Result::ObjectList.new(api_console.read("queues/#{queue_id}/items")) }
|
|
154
|
+
command :move_forwards, description: 'Move transfer forwards in queue',
|
|
104
155
|
arguments: [{name: :transfer_id, type: :identifier}]
|
|
105
|
-
command :
|
|
106
|
-
arguments: [{name: :transfer_id, type: :identifier}]
|
|
107
|
-
command :move_back, description: 'Move transfer backwards',
|
|
156
|
+
command :move_back, description: 'Move transfer backwards in queue',
|
|
108
157
|
arguments: [{name: :transfer_id, type: :identifier}]
|
|
109
158
|
end
|
|
110
159
|
|
|
160
|
+
# PUT queues/<queue_id>/items/<id>/<verb>
|
|
161
|
+
%i[move_forwards move_back].each do |verb|
|
|
162
|
+
define_action_method([:transfer, :queue, verb]) do |queue_id:, transfer_id:, **|
|
|
163
|
+
Result::SingleObject.new(api_console.update("queues/#{queue_id}/items/#{transfer_id}/#{verb}", {}))
|
|
164
|
+
end
|
|
165
|
+
end
|
|
166
|
+
|
|
111
167
|
# Generate one handler per transfer/current action.
|
|
112
168
|
# Convention: action_transfer_current_<verb>
|
|
113
|
-
# All share the same REST pattern:
|
|
114
|
-
%i[start pause cancel resume
|
|
115
|
-
define_action_method([:transfer, :current, verb]) do |
|
|
116
|
-
Result::SingleObject.new(api_console.update("transfers/#{transfer_id}/#{verb}",
|
|
169
|
+
# All share the same REST pattern: PUT transfers/<id>/<verb>.
|
|
170
|
+
%i[start pause cancel resume].each do |verb|
|
|
171
|
+
define_action_method([:transfer, :current, verb]) do |transfer_id:, **|
|
|
172
|
+
Result::SingleObject.new(api_console.update("transfers/#{transfer_id}/#{verb}", {}))
|
|
173
|
+
end
|
|
174
|
+
end
|
|
175
|
+
|
|
176
|
+
# PUT transfers/<id>/<verb> with request body
|
|
177
|
+
{change_rate: :rate, change_policy: :policy}.each do |verb, arg|
|
|
178
|
+
define_action_method([:transfer, :current, verb]) do |transfer_id:, **kwargs|
|
|
179
|
+
Result::SingleObject.new(api_console.update("transfers/#{transfer_id}/#{verb}", kwargs.fetch(arg)))
|
|
117
180
|
end
|
|
118
181
|
end
|
|
119
182
|
|
|
120
183
|
commands_under %i[transfer smart] do
|
|
121
|
-
command :list, description: 'List smart transfers', action: ->(
|
|
184
|
+
command :list, description: 'List smart transfers', action: ->(**) { Result::ObjectList.new(api_console.read('smart_transfers')) }
|
|
122
185
|
command :submit, description: 'Submit a smart transfer',
|
|
123
|
-
arguments: [{name: :smart_id}, {name: :
|
|
186
|
+
arguments: [{name: :smart_id, type: :identifier}, {name: :transfer, type: Hash, schema: Schema::Registry.req_body(Schema::Registry::CONSOLE, 'smart_transfers/{id}.post')}],
|
|
187
|
+
action: ->(smart_id:, transfer:, **) { Result::ObjectList.new(api_console.create("smart_transfers/#{smart_id}", transfer)) }
|
|
188
|
+
command :pause, description: 'Pause a smart transfer',
|
|
189
|
+
arguments: [{name: :smart_id, type: :identifier}],
|
|
190
|
+
action: ->(smart_id:, **) { Result::SingleObject.new(api_console.update("smart_transfers/#{smart_id}/pause", {})) }
|
|
124
191
|
end
|
|
125
192
|
|
|
126
|
-
# ---
|
|
193
|
+
# --- API ---
|
|
127
194
|
|
|
128
|
-
#
|
|
129
|
-
# @return [
|
|
130
|
-
def
|
|
131
|
-
|
|
195
|
+
# Console REST API, built from CLI options on first use.
|
|
196
|
+
# @return [Rest::Client]
|
|
197
|
+
def api_console
|
|
198
|
+
@api_console ||= basic_auth_api('api')
|
|
132
199
|
end
|
|
133
200
|
|
|
134
201
|
# --- health ---
|
|
135
202
|
|
|
136
|
-
def action_health(
|
|
203
|
+
def action_health(**)
|
|
137
204
|
nagios = Nagios.new
|
|
205
|
+
begin
|
|
206
|
+
# Unauthenticated, outside of the API prefix
|
|
207
|
+
Rest::Client.new(base_url: options.get_option(:url, mandatory: true)).read('health/up')
|
|
208
|
+
nagios.add_ok('console process', 'up')
|
|
209
|
+
rescue StandardError => e
|
|
210
|
+
nagios.add_critical('console process', e.to_s)
|
|
211
|
+
end
|
|
138
212
|
begin
|
|
139
213
|
api_console.read('ssh_keys')
|
|
140
214
|
nagios.add_ok('console api', 'accessible')
|
|
@@ -146,7 +220,7 @@ module Aspera
|
|
|
146
220
|
|
|
147
221
|
# --- transfer current ---
|
|
148
222
|
|
|
149
|
-
def action_transfer_current_list(
|
|
223
|
+
def action_transfer_current_list(**)
|
|
150
224
|
query = query_read_delete(default: {})
|
|
151
225
|
if query['from'].nil? && query['to'].nil?
|
|
152
226
|
time_now = Time.now
|
|
@@ -160,18 +234,8 @@ module Aspera
|
|
|
160
234
|
)
|
|
161
235
|
end
|
|
162
236
|
|
|
163
|
-
def action_transfer_current_files(api_console:, transfer_id:, **)
|
|
164
|
-
query = query_read_delete(default: {})
|
|
165
|
-
query['limit'] ||= 100
|
|
166
|
-
Result::ObjectList.new(api_console.read("transfers/#{transfer_id}/files", query))
|
|
167
|
-
end
|
|
168
|
-
|
|
169
237
|
# --- transfer smart ---
|
|
170
238
|
|
|
171
|
-
def action_transfer_smart_submit(api_console:, smart_id:, transfer_params:, **)
|
|
172
|
-
Result::ObjectList.new(api_console.create("smart_transfers/#{smart_id}", transfer_params))
|
|
173
|
-
end
|
|
174
|
-
|
|
175
239
|
private
|
|
176
240
|
|
|
177
241
|
def parse_extended_filter(filter, query)
|
|
@@ -11,13 +11,8 @@ module Aspera
|
|
|
11
11
|
class Cos < Base
|
|
12
12
|
application_name 'IBM Cloud Object Storage'
|
|
13
13
|
|
|
14
|
-
command :node, description: 'Execute COS node commands',
|
|
15
|
-
|
|
16
|
-
commands_under :node do
|
|
17
|
-
Node::COMMANDS_COS.each do |cmd|
|
|
18
|
-
command cmd, description: "Node #{cmd} command"
|
|
19
|
-
end
|
|
20
|
-
end
|
|
14
|
+
command :node, description: 'Execute COS node commands',
|
|
15
|
+
mount: {plugin: Node, instance: :cos_node_plugin, only: Node::COMMANDS_COS}
|
|
21
16
|
|
|
22
17
|
option :bucket, description: 'Bucket name'
|
|
23
18
|
option :endpoint, description: 'Storage endpoint (URL)'
|
|
@@ -29,14 +24,9 @@ module Aspera
|
|
|
29
24
|
|
|
30
25
|
use_options Node
|
|
31
26
|
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
end
|
|
36
|
-
|
|
37
|
-
# Build the COS Node API and plugin from CLI options.
|
|
38
|
-
# @return [Hash] context hash containing :node_plugin
|
|
39
|
-
def setup_cos_node(**)
|
|
27
|
+
# node - mount target: build the COS Node API and plugin from CLI options.
|
|
28
|
+
# @return [Node] Node plugin instance on the COS bucket
|
|
29
|
+
def cos_node_plugin(**)
|
|
40
30
|
# get service credentials, Hash, e.g. @json:@file:...
|
|
41
31
|
service_credentials = options.get_option(:service_credentials)
|
|
42
32
|
cos_node_params = {
|
|
@@ -53,14 +43,7 @@ module Aspera
|
|
|
53
43
|
cos_node_params.merge!(Api::CosNode.parameters_from_svc_credentials(service_credentials, options.get_option(:region, mandatory: true)))
|
|
54
44
|
end
|
|
55
45
|
api_node = Api::CosNode.new(**cos_node_params)
|
|
56
|
-
|
|
57
|
-
end
|
|
58
|
-
|
|
59
|
-
# One handler per COMMANDS_COS command - delegates to the Node plugin's dispatch_v3_command.
|
|
60
|
-
Node::COMMANDS_COS.each do |cmd|
|
|
61
|
-
define_action_method([:node, cmd]) do |node_plugin:|
|
|
62
|
-
node_plugin.dispatch_v3_command(cmd)
|
|
63
|
-
end
|
|
46
|
+
Node.new(context: context, api: api_node)
|
|
64
47
|
end
|
|
65
48
|
end
|
|
66
49
|
end
|
|
@@ -4,6 +4,7 @@ require 'singleton'
|
|
|
4
4
|
require 'aspera/assert'
|
|
5
5
|
require 'aspera/cli/error'
|
|
6
6
|
require 'aspera/environment'
|
|
7
|
+
require 'aspera/string_ext'
|
|
7
8
|
|
|
8
9
|
module Aspera
|
|
9
10
|
module Cli
|
|
@@ -29,7 +30,9 @@ module Aspera
|
|
|
29
30
|
end
|
|
30
31
|
|
|
31
32
|
# add a folder to the list of folders to look for plugins
|
|
33
|
+
# (absolute, as `require` resolves a relative path against $LOAD_PATH)
|
|
32
34
|
def add_lookup_folder(folder)
|
|
35
|
+
folder = File.expand_path(folder)
|
|
33
36
|
@lookup_folders.unshift(folder) unless @lookup_folders.include?(folder)
|
|
34
37
|
end
|
|
35
38
|
|