aspera-cli 4.26.2 → 4.27.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 +281 -21
- data/CONTRIBUTING.md +98 -7
- data/bin/ascli +3 -3
- data/docs/README.md +10757 -0
- data/docs/test-mcp-with-ai.md +202 -0
- data/lib/aspera/agent/base.rb +20 -6
- data/lib/aspera/agent/connect.rb +53 -16
- data/lib/aspera/agent/desktop.rb +52 -17
- data/lib/aspera/agent/direct.rb +26 -24
- data/lib/aspera/agent/httpgw.rb +1 -1
- data/lib/aspera/agent/node.rb +32 -0
- data/lib/aspera/agent/transferd.rb +39 -3
- data/lib/aspera/api/alee.rb +1 -1
- data/lib/aspera/api/aoc.rb +14 -16
- data/lib/aspera/api/cos_node.rb +1 -1
- data/lib/aspera/api/faspex.rb +15 -14
- data/lib/aspera/api/httpgw.rb +4 -4
- data/lib/aspera/api/node.rb +26 -23
- data/lib/aspera/api/queries/bss_subscription_account.graphql +18 -0
- data/lib/aspera/api/queries/bss_subscription_usage.graphql +18 -0
- data/lib/aspera/ascmd.rb +21 -19
- data/lib/aspera/ascp/installation.rb +37 -38
- data/lib/aspera/ascp/management.rb +2 -3
- data/lib/aspera/cli/ascp_actions.rb +155 -0
- data/lib/aspera/cli/async_transfer_store.rb +81 -0
- data/lib/aspera/cli/bootstrapper.rb +197 -0
- data/lib/aspera/cli/command_registry.rb +145 -0
- data/lib/aspera/cli/command_spec.rb +138 -0
- data/lib/aspera/cli/context.rb +16 -3
- data/lib/aspera/cli/error.rb +16 -0
- data/lib/aspera/cli/extended_value.rb +2 -1
- data/lib/aspera/cli/formatter.rb +41 -27
- data/lib/aspera/cli/gem_checker.rb +65 -0
- data/lib/aspera/cli/hints.rb +2 -2
- data/lib/aspera/cli/http.rb +70 -19
- data/lib/aspera/cli/info.rb +2 -0
- data/lib/aspera/cli/mailer.rb +97 -0
- data/lib/aspera/cli/mcp_tool.rb +198 -0
- data/lib/aspera/cli/options.schema.yaml +364 -7
- data/lib/aspera/cli/{manager.rb → parser.rb} +334 -142
- data/lib/aspera/cli/plugins/alee.rb +20 -22
- data/lib/aspera/cli/plugins/aoc.rb +1166 -853
- data/lib/aspera/cli/plugins/ats.rb +200 -161
- data/lib/aspera/cli/plugins/base.rb +457 -100
- data/lib/aspera/cli/plugins/basic_auth.rb +14 -4
- data/lib/aspera/cli/plugins/config.rb +428 -754
- data/lib/aspera/cli/plugins/console.rb +106 -64
- data/lib/aspera/cli/plugins/cos.rb +44 -32
- data/lib/aspera/cli/plugins/factory.rb +4 -4
- data/lib/aspera/cli/plugins/faspex.rb +294 -257
- data/lib/aspera/cli/plugins/faspex5.rb +585 -357
- data/lib/aspera/cli/plugins/faspio.rb +49 -51
- data/lib/aspera/cli/plugins/httpgw.rb +18 -25
- data/lib/aspera/cli/plugins/mcp.rb +279 -0
- data/lib/aspera/cli/plugins/node.rb +998 -794
- data/lib/aspera/cli/plugins/oauth.rb +7 -10
- data/lib/aspera/cli/plugins/orchestrator.rb +111 -134
- data/lib/aspera/cli/plugins/preview.rb +180 -139
- data/lib/aspera/cli/plugins/server.rb +124 -79
- data/lib/aspera/cli/plugins/shares.rb +301 -107
- data/lib/aspera/cli/preset_actions.rb +139 -0
- data/lib/aspera/cli/preset_manager.rb +13 -12
- data/lib/aspera/cli/result.rb +61 -11
- data/lib/aspera/cli/runner.rb +275 -141
- data/lib/aspera/cli/secret_finder.rb +40 -0
- data/lib/aspera/cli/special_values.rb +1 -0
- data/lib/aspera/cli/sync_actions.rb +83 -59
- data/lib/aspera/cli/terminal_formatter.rb +1 -1
- data/lib/aspera/cli/transfer_actions.rb +83 -0
- data/lib/aspera/cli/transfer_agent.rb +116 -51
- data/lib/aspera/cli/transfer_progress.rb +3 -3
- data/lib/aspera/cli/vault_manager.rb +57 -0
- data/lib/aspera/cli/version.rb +1 -1
- data/lib/aspera/cli/wizard.rb +21 -20
- data/lib/aspera/command_line_builder.rb +22 -22
- data/lib/aspera/data_repository.rb +2 -1
- data/lib/aspera/dot_container.rb +4 -4
- data/lib/aspera/environment.rb +18 -11
- data/lib/aspera/exec_spec.rb +13 -0
- data/lib/aspera/faspex_gw.rb +1 -1
- data/lib/aspera/faspex_postproc.rb +4 -3
- data/lib/aspera/graphql.rb +35 -0
- data/lib/aspera/hash_ext.rb +6 -0
- data/lib/aspera/json_rpc/client.rb +62 -0
- data/lib/aspera/json_rpc/version.rb +7 -0
- data/lib/aspera/keychain/encrypted_hash.rb +1 -1
- data/lib/aspera/keychain/factory.rb +3 -3
- data/lib/aspera/keychain/macos_security.rb +3 -3
- data/lib/aspera/link_header.rb +82 -0
- data/lib/aspera/log.rb +17 -3
- data/lib/aspera/markdown.rb +85 -2
- data/lib/aspera/node_simulator.rb +3 -1
- data/lib/aspera/oauth/base.rb +5 -5
- data/lib/aspera/oauth/boot.rb +2 -2
- data/lib/aspera/oauth/factory.rb +7 -5
- data/lib/aspera/oauth/jwt.rb +4 -4
- data/lib/aspera/oauth/web.rb +2 -2
- data/lib/aspera/persistency_action_once.rb +8 -8
- data/lib/aspera/persistency_folder.rb +10 -3
- data/lib/aspera/preview/file_types.rb +3 -3
- data/lib/aspera/preview/generator.rb +3 -3
- data/lib/aspera/preview/utils.rb +1 -1
- data/lib/aspera/products/connect.rb +1 -1
- data/lib/aspera/products/other.rb +1 -1
- data/lib/aspera/products/transferd.rb +1 -1
- data/lib/aspera/proxy_auto_config.rb +7 -6
- data/lib/aspera/rest.rb +10 -36
- data/lib/aspera/rest_error_analyzer.rb +3 -3
- data/lib/aspera/rest_errors_aspera.rb +0 -10
- data/lib/aspera/rest_list.rb +3 -3
- data/lib/aspera/schema/IBM Aspera on Cloud API-0.2.6-enhanced.yaml +1853 -510
- data/lib/aspera/schema/documentation.rb +57 -26
- data/lib/aspera/schema/reader.rb +59 -10
- data/lib/aspera/schema/registry.rb +39 -6
- data/lib/aspera/secret_hider.rb +7 -2
- data/lib/aspera/ssl.rb +4 -4
- data/lib/aspera/sync/conf.schema.yaml +2 -2
- data/lib/aspera/sync/operations.rb +10 -13
- data/lib/aspera/temp_file_manager.rb +1 -1
- data/lib/aspera/timer_limiter.rb +1 -1
- data/lib/aspera/transfer/faux_file.rb +24 -11
- data/lib/aspera/transfer/parameters.rb +23 -21
- data/lib/aspera/transfer/result.rb +74 -0
- data/lib/aspera/transfer/resumer.rb +6 -6
- data/lib/aspera/transfer/spec.rb +18 -1
- data/lib/aspera/transfer/spec.schema.yaml +12 -3
- data/lib/aspera/uri_reader.rb +2 -2
- data/lib/aspera/web_auth.rb +2 -2
- data/lib/aspera/web_server_simple.rb +8 -5
- data/lib/aspera/yaml.rb +2 -1
- data.tar.gz.sig +0 -0
- metadata +25 -3
- metadata.gz.sig +0 -0
- data/lib/aspera/json_rpc.rb +0 -52
|
@@ -5,6 +5,7 @@ require 'aspera/cli/version'
|
|
|
5
5
|
require 'aspera/cli/info'
|
|
6
6
|
require 'aspera/log'
|
|
7
7
|
require 'aspera/assert'
|
|
8
|
+
require 'aspera/yaml'
|
|
8
9
|
require 'digest'
|
|
9
10
|
require 'yaml'
|
|
10
11
|
|
|
@@ -39,7 +40,7 @@ module Aspera
|
|
|
39
40
|
read_config_file
|
|
40
41
|
end
|
|
41
42
|
|
|
42
|
-
attr_reader :config_presets, :use_plugin_defaults
|
|
43
|
+
attr_reader :config_file, :config_presets, :use_plugin_defaults
|
|
43
44
|
attr_writer :use_plugin_defaults
|
|
44
45
|
|
|
45
46
|
# ------------------------------------------------------------------
|
|
@@ -57,12 +58,12 @@ module Aspera
|
|
|
57
58
|
Log.log.debug{"config file is: #{@config_file}".red}
|
|
58
59
|
if File.exist?(@config_file)
|
|
59
60
|
Log.log.debug{"loading #{@config_file}"}
|
|
60
|
-
@config_presets =
|
|
61
|
+
@config_presets = Yaml.safe_load(File.read(@config_file))
|
|
61
62
|
@checksum_on_disk = checksum
|
|
62
63
|
else
|
|
63
64
|
Log.log.warn{"No config file found. New configuration file: #{@config_file}"}
|
|
64
65
|
@config_presets = {Key::CONFIG => {Key::VERSION => 'new file'}}
|
|
65
|
-
# @checksum_on_disk remains nil
|
|
66
|
+
# @checksum_on_disk remains nil: will be saved on first write
|
|
66
67
|
end
|
|
67
68
|
validate_config_presets!
|
|
68
69
|
rescue Psych::SyntaxError => e
|
|
@@ -82,13 +83,13 @@ module Aspera
|
|
|
82
83
|
# Save to disk only if content changed since last load/save.
|
|
83
84
|
# @return [Boolean] true if actually written
|
|
84
85
|
def save_if_needed
|
|
85
|
-
|
|
86
|
+
Aspera.assert(!@config_presets.nil?, type: Cli::Error){'no configuration loaded'}
|
|
86
87
|
current = checksum
|
|
87
88
|
return false if @checksum_on_disk.eql?(current)
|
|
88
89
|
FileUtils.mkdir_p(File.dirname(@config_file))
|
|
89
90
|
Environment.restrict_file_access(File.dirname(@config_file))
|
|
90
91
|
Log.log.info{"Saving config file: #{@config_file}"}
|
|
91
|
-
Environment.write_file_restricted(@config_file, force: true){
|
|
92
|
+
Environment.write_file_restricted(@config_file, force: true){@config_presets.to_yaml}
|
|
92
93
|
@checksum_on_disk = current
|
|
93
94
|
true
|
|
94
95
|
end
|
|
@@ -100,10 +101,10 @@ module Aspera
|
|
|
100
101
|
# @return [String, nil] name of the default preset for a plugin, or nil
|
|
101
102
|
def plugin_default_name(plugin_name_sym)
|
|
102
103
|
Aspera.assert(!@config_presets.nil?, 'config_presets shall be defined')
|
|
103
|
-
return
|
|
104
|
-
return
|
|
104
|
+
return unless @use_plugin_defaults
|
|
105
|
+
return unless @config_presets.key?(Key::DEFAULTS)
|
|
105
106
|
Aspera.assert_type(@config_presets[Key::DEFAULTS], Hash){'default section'}
|
|
106
|
-
return
|
|
107
|
+
return unless @config_presets[Key::DEFAULTS].key?(plugin_name_sym.to_s)
|
|
107
108
|
default_name = @config_presets[Key::DEFAULTS][plugin_name_sym.to_s]
|
|
108
109
|
unless @config_presets.key?(default_name)
|
|
109
110
|
Log.log.error do
|
|
@@ -123,14 +124,14 @@ module Aspera
|
|
|
123
124
|
# @param config_name [String]
|
|
124
125
|
# @param include_path [Array] guard against include loops
|
|
125
126
|
def by_name(config_name, include_path = [])
|
|
126
|
-
|
|
127
|
+
Aspera.assert(!include_path.include?(config_name), type: Cli::Error){'loop in include'}
|
|
127
128
|
include_path = include_path.clone
|
|
128
129
|
current = @config_presets
|
|
129
130
|
config_name.split(PRESET_DIG_SEPARATOR).each do |name|
|
|
130
131
|
Aspera.assert_type(current, Hash, type: Cli::Error){"sub key: #{include_path}"}
|
|
131
132
|
include_path.push(name)
|
|
132
133
|
current = current[name]
|
|
133
|
-
|
|
134
|
+
Aspera.assert(!current.nil?, type: Cli::Error){"Unknown config preset: #{include_path}"}
|
|
134
135
|
end
|
|
135
136
|
current = self.class.deep_clone(current) unless current.is_a?(String)
|
|
136
137
|
ExtendedValue.instance.evaluate(current, context: 'preset')
|
|
@@ -212,7 +213,7 @@ module Aspera
|
|
|
212
213
|
|
|
213
214
|
private
|
|
214
215
|
|
|
215
|
-
#
|
|
216
|
+
# Normalize a URL for comparison
|
|
216
217
|
def canonical_url(url)
|
|
217
218
|
url.chomp('/').sub(%r{^(https://[^/]+):443$}, '\1')
|
|
218
219
|
end
|
|
@@ -223,7 +224,7 @@ module Aspera
|
|
|
223
224
|
Aspera.assert_type(@config_presets, Hash){'config file YAML'}
|
|
224
225
|
Aspera.assert(@config_presets.key?(Key::CONFIG)){"Cannot find key: #{Key::CONFIG}"}
|
|
225
226
|
version = @config_presets[Key::CONFIG][Key::VERSION]
|
|
226
|
-
|
|
227
|
+
Aspera.assert(!version.nil?, type: Cli::Error){'No version found in config section.'}
|
|
227
228
|
Log.log.debug{"conf version: #{version}"}
|
|
228
229
|
# Fix bug in 4.4 (creating key "true" in "default" preset)
|
|
229
230
|
@config_presets[Key::DEFAULTS].delete(true) if @config_presets[Key::DEFAULTS].is_a?(Hash)
|
data/lib/aspera/cli/result.rb
CHANGED
|
@@ -34,7 +34,7 @@ module Aspera
|
|
|
34
34
|
# Base implementation handles common formats: text, nagios, ruby, json, jsonpp, yaml
|
|
35
35
|
# Subclasses should call super first, then handle their specific formats
|
|
36
36
|
# @param formatter [Formatter] The formatter to use
|
|
37
|
-
# @return [
|
|
37
|
+
# @return [nil]
|
|
38
38
|
def format(formatter)
|
|
39
39
|
# Apply field filtering once for formats that need it
|
|
40
40
|
filtered_data = formatter.filter_list_on_fields(@data)
|
|
@@ -72,14 +72,16 @@ module Aspera
|
|
|
72
72
|
rescue URI::InvalidURIError
|
|
73
73
|
@data
|
|
74
74
|
end
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
75
|
+
unless data.eql?(:done)
|
|
76
|
+
# try base64
|
|
77
|
+
data = begin
|
|
78
|
+
Base64.strict_decode64(data)
|
|
79
|
+
rescue ArgumentError
|
|
80
|
+
data
|
|
81
|
+
end
|
|
82
|
+
# here, data is the image blob
|
|
83
|
+
formatter.display_message(:data, Preview::Terminal.build(data, **formatter.image_options))
|
|
80
84
|
end
|
|
81
|
-
# here, data is the image blob
|
|
82
|
-
formatter.display_message(:data, Preview::Terminal.build(data, **formatter.image_options)) unless data.eql?(:done)
|
|
83
85
|
else
|
|
84
86
|
Aspera.error_unexpected_value(formatter.format_type){'format'}
|
|
85
87
|
end
|
|
@@ -189,7 +191,7 @@ module Aspera
|
|
|
189
191
|
|
|
190
192
|
def format(formatter)
|
|
191
193
|
# Force image format for Image results
|
|
192
|
-
formatter.
|
|
194
|
+
formatter.format_type = :image
|
|
193
195
|
super
|
|
194
196
|
end
|
|
195
197
|
end
|
|
@@ -234,8 +236,7 @@ module Aspera
|
|
|
234
236
|
# @param fields [Array<String>, Proc, nil] Fields to display in table/csv format
|
|
235
237
|
# @param total [Integer, nil] Total number of items available (for pagination display)
|
|
236
238
|
def initialize(data, fields: nil, total: nil)
|
|
237
|
-
Aspera.
|
|
238
|
-
raise ArgumentError, 'Object list result requires Array of Hash' unless data.all?(Hash)
|
|
239
|
+
Aspera.assert_array_all(data, Hash, type: ArgumentError){'object list result data'}
|
|
239
240
|
Aspera.assert_type(total, Integer, NilClass){'total'}
|
|
240
241
|
super(data: data, fields: fields)
|
|
241
242
|
@total = total
|
|
@@ -273,6 +274,16 @@ module Aspera
|
|
|
273
274
|
case formatter.format_type
|
|
274
275
|
when :table, :csv
|
|
275
276
|
formatter.display_table(@data.map{ |i| {@name => i}}, [@name])
|
|
277
|
+
when :text
|
|
278
|
+
formatter.display_message(:data, @data.join("\n"))
|
|
279
|
+
when :ruby
|
|
280
|
+
formatter.display_message(:data, PP.pp(@data, +''))
|
|
281
|
+
when :json
|
|
282
|
+
formatter.display_message(:data, JSON.generate(@data))
|
|
283
|
+
when :jsonpp
|
|
284
|
+
formatter.display_message(:data, JSON.pretty_generate(@data))
|
|
285
|
+
when :yaml
|
|
286
|
+
formatter.display_message(:data, YAML.dump(@data))
|
|
276
287
|
else
|
|
277
288
|
super
|
|
278
289
|
end
|
|
@@ -280,6 +291,45 @@ module Aspera
|
|
|
280
291
|
end
|
|
281
292
|
|
|
282
293
|
class << self
|
|
294
|
+
# Execute a bulk operation over a list of already-resolved items and return a CLI result.
|
|
295
|
+
# This is a pure helper: it reads nothing from the CLI.
|
|
296
|
+
# @param items [Array] List of items to process (one element when non-bulk)
|
|
297
|
+
# @param is_bulk [Boolean] Whether the caller is in bulk mode
|
|
298
|
+
# @param command [Symbol] Operation name (:create, :delete, …) used to build the past-tense status string
|
|
299
|
+
# @param id_result [String] Key in the result Hash used as item identifier
|
|
300
|
+
# @param fields [Object] Fields hint passed to the Result constructor (non-bulk only, when not :default)
|
|
301
|
+
# @param bfail [Boolean] When true, re-raise errors; when false, capture them as a status string
|
|
302
|
+
# @yieldparam item [Object] Each item in +items+
|
|
303
|
+
# @yieldreturn [Hash, Array, nil] REST response; a Hash replaces the default id-keyed result
|
|
304
|
+
# @return [Result::ObjectList, Result::SingleObject]
|
|
305
|
+
def bulk(items, is_bulk:, command:, id_result: 'id', fields: :default, bfail: true)
|
|
306
|
+
Aspera.assert(block_given?, 'missing block')
|
|
307
|
+
Log.log.warn('Empty list given for bulk operation') if items.empty?
|
|
308
|
+
Log.dump(:bulk_operation, items)
|
|
309
|
+
result_list = []
|
|
310
|
+
items.each do |item|
|
|
311
|
+
result = {id_result => item}
|
|
312
|
+
begin
|
|
313
|
+
res = yield(item)
|
|
314
|
+
result = res if res.is_a?(Hash)
|
|
315
|
+
# TODO: remove when faspio gw api fixes this
|
|
316
|
+
result = res.first if res.is_a?(Array) && res.first.is_a?(Hash)
|
|
317
|
+
result['status'] = "#{command}#{'e' unless command.to_s.end_with?('e')}d".gsub(/yed$/, 'ied')
|
|
318
|
+
rescue StandardError => e
|
|
319
|
+
raise e if bfail
|
|
320
|
+
result['status'] = e.to_s
|
|
321
|
+
end
|
|
322
|
+
result_list.push(result)
|
|
323
|
+
end
|
|
324
|
+
display_fields = [id_result, 'status']
|
|
325
|
+
if is_bulk
|
|
326
|
+
return ObjectList.new(result_list, fields: display_fields)
|
|
327
|
+
else
|
|
328
|
+
display_fields = fields unless fields.eql?(:default)
|
|
329
|
+
return SingleObject.new(result_list.first, fields: display_fields)
|
|
330
|
+
end
|
|
331
|
+
end
|
|
332
|
+
|
|
283
333
|
# Class method to automatically determine result type from data
|
|
284
334
|
# @param data [Object] the data to analyze and format
|
|
285
335
|
# @return [Result]
|