aspera-cli 4.27.2 → 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.
Files changed (130) hide show
  1. checksums.yaml +4 -4
  2. checksums.yaml.gz.sig +0 -0
  3. data/CHANGELOG.md +50 -0
  4. data/bin/ascli +2 -1
  5. data/docs/README.md +804 -746
  6. data/lib/aspera/agent/connect.rb +6 -4
  7. data/lib/aspera/agent/desktop.rb +2 -2
  8. data/lib/aspera/agent/direct.rb +3 -1
  9. data/lib/aspera/agent/node.rb +3 -3
  10. data/lib/aspera/api/alee.rb +1 -1
  11. data/lib/aspera/api/aoc.rb +14 -12
  12. data/lib/aspera/api/ats.rb +1 -1
  13. data/lib/aspera/api/cos_node.rb +2 -2
  14. data/lib/aspera/api/faspex.rb +9 -7
  15. data/lib/aspera/api/httpgw.rb +37 -33
  16. data/lib/aspera/api/node.rb +38 -33
  17. data/lib/aspera/ascmd.rb +3 -1
  18. data/lib/aspera/ascp/installation.rb +62 -27
  19. data/lib/aspera/ascp/management.rb +1 -0
  20. data/lib/aspera/assert.rb +4 -0
  21. data/lib/aspera/cli/ascp_actions.rb +20 -41
  22. data/lib/aspera/cli/async_transfer_store.rb +2 -2
  23. data/lib/aspera/cli/bootstrapper.rb +11 -15
  24. data/lib/aspera/cli/command_line.rb +252 -0
  25. data/lib/aspera/cli/command_registry.rb +149 -33
  26. data/lib/aspera/cli/command_spec.rb +103 -14
  27. data/lib/aspera/cli/completion/ascli.bash +12 -0
  28. data/lib/aspera/cli/completion/ascli.fish +16 -0
  29. data/lib/aspera/cli/completion/ascli.zsh +19 -0
  30. data/lib/aspera/cli/context.rb +3 -0
  31. data/lib/aspera/cli/deprecation.rb +37 -0
  32. data/lib/aspera/cli/extended_value.rb +2 -0
  33. data/lib/aspera/cli/formatter.rb +87 -75
  34. data/lib/aspera/cli/gem_checker.rb +1 -1
  35. data/lib/aspera/cli/hints.rb +7 -6
  36. data/lib/aspera/cli/http.rb +21 -21
  37. data/lib/aspera/cli/info.rb +3 -0
  38. data/lib/aspera/cli/mcp_tool.rb +47 -83
  39. data/lib/aspera/cli/option_declarator.rb +33 -42
  40. data/lib/aspera/cli/option_registry.rb +69 -0
  41. data/lib/aspera/cli/option_types.rb +103 -0
  42. data/lib/aspera/cli/option_value.rb +281 -0
  43. data/lib/aspera/cli/options.schema.yaml +38 -5
  44. data/lib/aspera/cli/parser.rb +307 -848
  45. data/lib/aspera/cli/plugins/alee.rb +7 -4
  46. data/lib/aspera/cli/plugins/aoc.rb +430 -380
  47. data/lib/aspera/cli/plugins/ats.rb +58 -73
  48. data/lib/aspera/cli/plugins/base.rb +190 -240
  49. data/lib/aspera/cli/plugins/basic_auth.rb +2 -10
  50. data/lib/aspera/cli/plugins/config.rb +244 -178
  51. data/lib/aspera/cli/plugins/console.rb +102 -38
  52. data/lib/aspera/cli/plugins/cos.rb +6 -23
  53. data/lib/aspera/cli/plugins/factory.rb +3 -0
  54. data/lib/aspera/cli/plugins/faspex5.rb +176 -173
  55. data/lib/aspera/cli/plugins/faspio.rb +5 -10
  56. data/lib/aspera/cli/plugins/httpgw.rb +8 -11
  57. data/lib/aspera/cli/plugins/mcp.rb +20 -55
  58. data/lib/aspera/cli/plugins/node.rb +277 -311
  59. data/lib/aspera/cli/plugins/orchestrator.rb +90 -77
  60. data/lib/aspera/cli/plugins/preview.rb +79 -90
  61. data/lib/aspera/cli/plugins/server.rb +76 -50
  62. data/lib/aspera/cli/plugins/shares.rb +68 -116
  63. data/lib/aspera/cli/preset_actions.rb +17 -10
  64. data/lib/aspera/cli/preset_manager.rb +12 -2
  65. data/lib/aspera/cli/prompt.rb +35 -0
  66. data/lib/aspera/cli/result.rb +13 -18
  67. data/lib/aspera/cli/runner.rb +31 -54
  68. data/lib/aspera/cli/special_values.rb +5 -0
  69. data/lib/aspera/cli/sync_actions.rb +41 -37
  70. data/lib/aspera/cli/terminal_formatter.rb +9 -3
  71. data/lib/aspera/cli/transfer_actions.rb +0 -6
  72. data/lib/aspera/cli/transfer_agent.rb +29 -35
  73. data/lib/aspera/cli/vault_manager.rb +0 -17
  74. data/lib/aspera/cli/version.rb +1 -1
  75. data/lib/aspera/cli/wizard.rb +4 -2
  76. data/lib/aspera/coverage.rb +1 -0
  77. data/lib/aspera/environment.rb +6 -0
  78. data/lib/aspera/faspex_gw.rb +2 -1
  79. data/lib/aspera/faspex_postproc.rb +1 -0
  80. data/lib/aspera/graphql.rb +5 -5
  81. data/lib/aspera/json_rpc/client.rb +5 -5
  82. data/lib/aspera/keychain/encrypted_hash.rb +1 -1
  83. data/lib/aspera/keychain/one_password_api.rb +1 -1
  84. data/lib/aspera/link_header.rb +2 -2
  85. data/lib/aspera/log.rb +22 -25
  86. data/lib/aspera/markdown.rb +2 -0
  87. data/lib/aspera/mime.rb +25 -0
  88. data/lib/aspera/node_simulator.rb +1 -0
  89. data/lib/aspera/oauth/base.rb +35 -25
  90. data/lib/aspera/oauth/factory.rb +1 -0
  91. data/lib/aspera/oauth/generic.rb +1 -1
  92. data/lib/aspera/oauth/jwt.rb +1 -1
  93. data/lib/aspera/oauth/web.rb +9 -8
  94. data/lib/aspera/preview/file_types.rb +4 -4
  95. data/lib/aspera/preview/generator.rb +7 -0
  96. data/lib/aspera/preview/options.rb +4 -4
  97. data/lib/aspera/preview/terminal.rb +4 -3
  98. data/lib/aspera/preview/utils.rb +9 -6
  99. data/lib/aspera/products/connect.rb +1 -1
  100. data/lib/aspera/rainbow.rb +7 -0
  101. data/lib/aspera/rest/aspera_errors.rb +60 -0
  102. data/lib/aspera/rest/call_error.rb +27 -0
  103. data/lib/aspera/rest/client.rb +514 -0
  104. data/lib/aspera/rest/error_analyzer.rb +113 -0
  105. data/lib/aspera/rest/list.rb +143 -0
  106. data/lib/aspera/rest/parameters.rb +55 -0
  107. data/lib/aspera/rest/util.rb +176 -0
  108. data/lib/aspera/rest.rb +7 -621
  109. data/lib/aspera/schema/IBM Aspera Console-enhanced.yaml +1125 -0
  110. data/lib/aspera/schema/IBM Aspera on Cloud Automation API-1.0.5-enhanced.yaml +2395 -0
  111. data/lib/aspera/schema/documentation.rb +13 -3
  112. data/lib/aspera/schema/registry.rb +18 -1
  113. data/lib/aspera/schema/validator.rb +92 -0
  114. data/lib/aspera/secret_hider.rb +36 -25
  115. data/lib/aspera/string_ext.rb +15 -0
  116. data/lib/aspera/temp_file_manager.rb +6 -5
  117. data/lib/aspera/transfer/parameters.rb +2 -0
  118. data/lib/aspera/transfer/spec.rb +1 -0
  119. data/lib/aspera/uri_reader.rb +11 -11
  120. data/lib/aspera/web_auth/index.html +147 -0
  121. data/lib/aspera/web_auth/server.rb +81 -0
  122. data.tar.gz.sig +0 -0
  123. metadata +39 -7
  124. metadata.gz.sig +0 -0
  125. data/lib/aspera/colors.rb +0 -79
  126. data/lib/aspera/rest_call_error.rb +0 -25
  127. data/lib/aspera/rest_error_analyzer.rb +0 -111
  128. data/lib/aspera/rest_errors_aspera.rb +0 -58
  129. data/lib/aspera/rest_list.rb +0 -136
  130. data/lib/aspera/web_auth.rb +0 -211
@@ -0,0 +1,12 @@
1
+ # Bash completion for ascli
2
+ # Activate: eval "$(ascli config completion bash)"
3
+
4
+ _ascli_complete() {
5
+ local cur="${COMP_WORDS[COMP_CWORD]}"
6
+ # COMP_WORDS[0] is the program name itself; pass only the words typed before the cursor
7
+ local candidates
8
+ candidates=$(ascli config completion words "${COMP_WORDS[@]:1:COMP_CWORD-1}" 2>/dev/null)
9
+ COMPREPLY=( $(compgen -W "${candidates}" -- "${cur}") )
10
+ }
11
+
12
+ complete -F _ascli_complete ascli
@@ -0,0 +1,16 @@
1
+ # Fish completion for ascli
2
+ # Activate: ascli config completion fish | source
3
+ # Or save as file ~/.config/fish/completions/ascli.fish
4
+
5
+ # Remove completions of a previous activation
6
+ complete --command ascli --erase
7
+
8
+ # Disable file completion entirely — ascli manages its own argument tree
9
+ complete --command ascli --no-files
10
+
11
+ # Dynamic completion: pass all words already typed (excluding 'ascli' itself)
12
+ # to `ascli config completion words` and return the result as completions.
13
+ complete --command ascli --arguments '(
14
+ set -l words (commandline -opc)
15
+ ascli config completion words $words[2..] 2>/dev/null
16
+ )'
@@ -0,0 +1,19 @@
1
+ #compdef ascli
2
+ # Zsh completion for ascli
3
+ # Activate (after compinit): eval "$(ascli config completion zsh)"
4
+ # Or save as file `_ascli` in a folder of $fpath
5
+
6
+ _ascli() {
7
+ local -a candidates
8
+ # words[1] is 'ascli' itself; pass only the words typed before the cursor
9
+ candidates=(${(f)"$(ascli config completion words "${(@)words[2,CURRENT-1]}" 2>/dev/null)"})
10
+ compadd -a candidates
11
+ }
12
+
13
+ if [[ "${funcstack[1]}" == _ascli ]]; then
14
+ # Autoloaded from $fpath: this file is the body of function _ascli
15
+ _ascli "$@"
16
+ else
17
+ # Evaluated or sourced
18
+ compdef _ascli ascli
19
+ fi
@@ -36,6 +36,8 @@ module Aspera
36
36
  attr_accessor :progress_bar
37
37
  # Optional: nil when no PAC script is configured
38
38
  attr_accessor :pac_executor
39
+ # `true` when help is requested (`-h`)
40
+ attr_accessor :help_requested
39
41
 
40
42
  # Initialize all members to nil, so that they are defined and can be validated later
41
43
  # @return [nil]
@@ -43,6 +45,7 @@ module Aspera
43
45
  MEMBERS.each { |i| instance_variable_set(:"@#{i}", nil) }
44
46
  @progress_bar = nil
45
47
  @pac_executor = nil
48
+ @help_requested = false
46
49
  end
47
50
 
48
51
  # Validate that all mandatory members are non-nil (detect bootstrap bugs)
@@ -0,0 +1,37 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'aspera/cli/version'
4
+ require 'aspera/assert'
5
+
6
+ module Aspera
7
+ module Cli
8
+ # Deprecation of a feature (e.g. an option).
9
+ # @!attribute last [String] Last released version supporting the feature without deprecation, e.g. `4.25.0`
10
+ # @!attribute message [String] What to use instead, e.g. `use --out.level`
11
+ Deprecation = Struct.new(:last, :message, keyword_init: true) do
12
+ def initialize(**kwargs)
13
+ super
14
+ Aspera.assert_type(last, String) { 'deprecation last' }
15
+ Aspera.assert(Gem::Version.correct?(last) && Gem::Version.new(last) < Gem::Version.new(VERSION)) do
16
+ "deprecation: last (#{last}) must be a released version, before #{VERSION}"
17
+ end
18
+ Aspera.assert_type(message, String) { 'deprecation message' }
19
+ end
20
+
21
+ # @return [String] e.g. `deprecated after 4.25.0: use --out.level`
22
+ def to_s = "deprecated after #{last}: #{message}"
23
+
24
+ class << self
25
+ # @param value [Deprecation, Hash, nil] Deprecation, or its attributes: `{last:, message:}`
26
+ # @return [Deprecation, nil]
27
+ def create(value)
28
+ case value
29
+ when nil, Deprecation then value
30
+ when Hash then new(**value)
31
+ else Aspera.error_unexpected_value(value.class) { 'deprecation, expect Hash {last:, message:}' }
32
+ end
33
+ end
34
+ end
35
+ end
36
+ end
37
+ end
@@ -12,6 +12,8 @@ require 'base64'
12
12
  require 'zlib'
13
13
  require 'csv'
14
14
  require 'singleton'
15
+ require 'aspera/rainbow'
16
+ using Rainbow
15
17
 
16
18
  module Aspera
17
19
  module Cli
@@ -18,6 +18,8 @@ require 'yaml'
18
18
  require 'pp'
19
19
  require 'csv'
20
20
  require 'word_wrap'
21
+ require 'aspera/rainbow'
22
+ using Rainbow
21
23
 
22
24
  module Aspera
23
25
  module Cli
@@ -25,7 +27,7 @@ module Aspera
25
27
  class Formatter
26
28
  extend OptionDeclarator
27
29
 
28
- # remove a fields from the list
30
+ # `-` remove a fields from the list
29
31
  FIELDS_LESS = '-'
30
32
  # supported output formats
31
33
  DISPLAY_FORMATS = %i[text nagios ruby json jsonpp yaml table csv image].freeze
@@ -38,17 +40,17 @@ module Aspera
38
40
 
39
41
  private_constant :FIELDS_LESS, :DISPLAY_FORMATS, :DISPLAY_LEVELS, :SINGLE_OBJECT_COLUMN_NAMES, :STR_LST_SEP_VERT
40
42
 
41
- option :out, description: 'Output rendering options (dot-notation: format, level, file, fields, select, table[.pivot], flat, secrets, img)', schema: Schema::Registry::OUT_OPTIONS
42
- option :display, description: 'Output only some information', allowed: DISPLAY_LEVELS, default: :data, deprecation: 'use --out.level'
43
+ option :out, description: 'Output rendering options (dot-notation: format, level, file, fields, select, table[.pivot], flat, secrets, colors, utf8, img)', schema: Schema::Registry::OUT_OPTIONS
44
+ option :display, description: 'Output only some information', allowed: DISPLAY_LEVELS, default: :data, deprecation: {last: '4.27.0', message: 'use --out.level'}
43
45
  option :format, description: 'Output format (also: --out.format)', allowed: DISPLAY_FORMATS, default: :table
44
- option :output, description: 'Destination for results', deprecation: 'use --out.file'
46
+ option :output, description: 'Destination for results', deprecation: {last: '4.27.0', message: 'use --out.file'}
45
47
  option :fields, description: "Comma separated list of: fields, or #{SpecialValues::ALL}, or #{SpecialValues::DEF} (also: --out.fields)", allowed: [String, Array, Regexp, Proc], default: SpecialValues::DEF
46
48
  option :select, description: 'Select only some items in lists: column, value (also: --out.select)', allowed: [Hash, Proc]
47
- option :table_style, description: '(Table) Display style', allowed: [Hash], deprecation: 'use --out.table'
48
- option :flat_hash, description: '(Table) Display deep values as additional keys', allowed: Type::BOOLEAN, default: true, deprecation: 'use --out.flat'
49
- option :multi_single, description: '(Table) Control how object list is displayed as single table, or multiple objects', allowed: %i[no yes single], default: :no, deprecation: 'use --out.table.pivot'
50
- option :show_secrets, description: 'Show secrets on command output', allowed: Type::BOOLEAN, default: false, deprecation: 'use --out.secrets'
51
- option :image, schema: Schema::Registry::IMAGE_OPTIONS, deprecation: 'use --out.img'
49
+ option :table_style, description: '(Table) Display style', allowed: [Hash], deprecation: {last: '4.27.0', message: 'use --out.table'}
50
+ option :flat_hash, description: '(Table) Display deep values as additional keys', allowed: Type::BOOLEAN, default: true, deprecation: {last: '4.27.0', message: 'use --out.flat'}
51
+ option :multi_single, description: '(Table) Control how object list is displayed as single table, or multiple objects', allowed: %i[no yes single], default: :no, deprecation: {last: '4.27.0', message: 'use --out.table.pivot'}
52
+ option :show_secrets, description: 'Show secrets on command output', allowed: Type::BOOLEAN, default: false, deprecation: {last: '4.27.0', message: 'use --out.secrets'}
53
+ option :image, schema: Schema::Registry::IMAGE_OPTIONS, deprecation: {last: '4.27.0', message: 'use --out.img'}
52
54
 
53
55
  class << self
54
56
  # Replace special values with a readable version on terminal
@@ -85,14 +87,21 @@ module Aspera
85
87
  end
86
88
  end
87
89
 
88
- def all_but(list)
89
- Array(list).map { |i| "#{FIELDS_LESS}#{i}" }.unshift(SpecialValues::ALL)
90
+ # @param fields [Array<String>] List of fields to not display
91
+ # @return [Array<String>] List of fields to display, including special values (`ALL`) and tagged (`-`) fields
92
+ def all_but(*fields)
93
+ Aspera.assert_array_all(fields, String)
94
+ fields.map { |i| "#{FIELDS_LESS}#{i}" }.unshift(SpecialValues::ALL)
90
95
  end
91
96
  end
92
97
 
93
98
  # initialize the formatter
94
99
  def initialize
95
100
  @options = {}
101
+ # Last value of option `out`
102
+ @out_dispatched = {}
103
+ # Colors auto-detected by Rainbow at load time, restored when `--out.colors` is reset
104
+ @colors_detected = Rainbow.enabled
96
105
  @spinner = nil
97
106
  end
98
107
 
@@ -103,7 +112,7 @@ module Aspera
103
112
  total = total.to_i
104
113
  return if total.eql?(0) && count.eql?(0)
105
114
  count_msg = "Items: #{count}/#{total}"
106
- count_msg = count_msg.bg_red unless count.eql?(total)
115
+ count_msg = count_msg.bg(:red) unless count.eql?(total)
107
116
  display_status(count_msg)
108
117
  end
109
118
 
@@ -137,72 +146,68 @@ module Aspera
137
146
  end
138
147
  end
139
148
 
140
- # Bind all formatter options to this instance using set_handler.
149
+ # Bind all formatter options to this instance using `on_set`.
141
150
  # Called from Runner after Formatter.new.
142
151
  # @param options [Aspera::Cli::Parser]
143
152
  # @return [nil]
144
153
  def bind_options(options)
145
154
  @parser = options
146
155
  %i[out display format output fields select table_style flat_hash multi_single show_secrets image].each do |opt|
147
- options.set_handler(opt, object: self, method: :option_handler)
156
+ options.on_set(opt, ->(value) { option_handler(opt, value) })
148
157
  end
149
158
  nil
150
159
  end
151
160
 
152
- # Getter/setter handler called by the option manager for all formatter options
153
- # @param option_symbol [Symbol] Option name (one of :out, :format, :output, :display, :fields, :select, :table_style, :flat_hash, :multi_single, :show_secrets, :image)
154
- # @param operation [Symbol] :get or :set
155
- # @param value [Object, nil] Value to set (only used when operation is :set)
156
- # @return [Object, nil] Current option value when operation is :get; nil otherwise
157
- def option_handler(option_symbol, operation, value = nil)
158
- Aspera.assert_values(operation, %i[set get])
159
- case operation
160
- when :set
161
- # --out is a composite hash: dispatch each sub-key through the parser (validation included)
162
- if option_symbol.eql?(:out)
163
- Aspera.assert_type(value, Hash)
164
- value.each do |k, v|
165
- case k.to_sym
166
- when :format then @parser.set_option(:format, v, warn_deprecation: false)
167
- when :level then @parser.set_option(:display, v, warn_deprecation: false)
168
- when :file then @parser.set_option(:output, v, warn_deprecation: false)
169
- when :fields then @parser.set_option(:fields, v, warn_deprecation: false)
170
- when :select then @parser.set_option(:select, v, warn_deprecation: false)
171
- when :table
172
- Aspera.assert_type(v, Hash)
173
- table_hash = v.transform_keys(&:to_sym)
174
- @parser.set_option(:multi_single, table_hash.delete(:pivot).to_s, warn_deprecation: false) if table_hash.key?(:pivot)
175
- @parser.set_option(:table_style, table_hash, warn_deprecation: false) unless table_hash.empty?
176
- when :flat then @parser.set_option(:flat_hash, v, warn_deprecation: false)
177
- when :secrets then @parser.set_option(:show_secrets, v, warn_deprecation: false)
178
- when :img then @parser.set_option(:image, v, warn_deprecation: false)
179
- else Aspera.error_unexpected_value(k) { 'out sub-option (format, level, file, fields, select, table[.pivot], flat, secrets, img)' }
180
- end
161
+ # `on_set` callback called by the option manager for all formatter options
162
+ # @param option_symbol [Symbol] Option name (one of :out, :format, :output, :display, :fields, :select, :table_style, :flat_hash, :multi_single, :show_secrets, :image)
163
+ # @param value [Object, nil] New value
164
+ # @return [nil]
165
+ def option_handler(option_symbol, value)
166
+ # --out is a composite hash: dispatch each sub-key through the parser (validation included)
167
+ if option_symbol.eql?(:out)
168
+ Aspera.assert_type(value, Hash)
169
+ # Value is merged with previous values: dispatch only changes
170
+ changed = value.reject { |k, v| @out_dispatched[k].eql?(v) }
171
+ @out_dispatched = value
172
+ changed.each do |k, v|
173
+ case k.to_sym
174
+ when :format then @parser.set_option(:format, v, warn_deprecation: false)
175
+ when :level then @parser.set_option(:display, v, warn_deprecation: false)
176
+ when :file then @parser.set_option(:output, v, warn_deprecation: false)
177
+ when :fields then @parser.set_option(:fields, v, warn_deprecation: false)
178
+ when :select then @parser.set_option(:select, v, warn_deprecation: false)
179
+ when :table
180
+ Aspera.assert_type(v, Hash)
181
+ table_hash = v.transform_keys(&:to_sym)
182
+ @parser.set_option(:multi_single, table_hash.delete(:pivot), warn_deprecation: false) if table_hash.key?(:pivot)
183
+ @parser.set_option(:table_style, table_hash, warn_deprecation: false) unless table_hash.empty?
184
+ when :flat then @parser.set_option(:flat_hash, v, warn_deprecation: false)
185
+ when :secrets then @parser.set_option(:show_secrets, v, warn_deprecation: false)
186
+ when :img then @parser.set_option(:image, v, warn_deprecation: false)
187
+ when :colors then Rainbow.enabled = v.nil? ? @colors_detected : v
188
+ when :utf8 then Environment.unicode = v
189
+ else Aspera.error_unexpected_value(k) { 'out sub-option (format, level, file, fields, select, table[.pivot], flat, secrets, colors, utf8, img)' }
181
190
  end
182
- return
183
191
  end
184
- @options[option_symbol] = value
185
- # special handling of some options
186
- case option_symbol
187
- when :format
188
- @options[:display] = value.eql?(:table) ? :info : :data
189
- when :output
190
- $stdout = if value.eql?('-')
191
- STDOUT # rubocop:disable Style/GlobalStdStream
192
- else
193
- File.open(value, 'w')
194
- end
195
- when :image
196
- # get list if key arguments of method
197
- allowed_options = Preview::Terminal.method(:build).parameters.select { |i| i[0].eql?(:key) }.map { |i| i[1] }
198
- # check that only supported options are given
199
- unknown_options = value.keys.map(&:to_sym) - allowed_options
200
- Aspera.assert(unknown_options.empty?) { "Invalid parameter(s) for option image: #{unknown_options.join(', ')}, use #{allowed_options.join(', ')}" }
192
+ return
193
+ end
194
+ @options[option_symbol] = value
195
+ # special handling of some options
196
+ case option_symbol
197
+ when :format
198
+ @options[:display] = value.eql?(:table) ? :info : :data
199
+ when :output
200
+ $stdout = if value.eql?('-')
201
+ STDOUT # rubocop:disable Style/GlobalStdStream
202
+ else
203
+ File.open(value, 'w')
201
204
  end
202
- when :get
203
- return if option_symbol.eql?(:out)
204
- return @options[option_symbol]
205
- else Aspera.error_unreachable_line
205
+ when :image
206
+ # get list if key arguments of method
207
+ allowed_options = Preview::Terminal.method(:build).parameters.select { |i| i[0].eql?(:key) }.map { |i| i[1] }
208
+ # check that only supported options are given
209
+ unknown_options = value.keys.map(&:to_sym) - allowed_options
210
+ Aspera.assert(unknown_options.empty?) { "Invalid parameter(s) for option image: #{unknown_options.join(', ')}, use #{allowed_options.join(', ')}" }
206
211
  end
207
212
  nil
208
213
  end
@@ -214,9 +219,9 @@ module Aspera
214
219
  # @param hide_secrets [Boolean] Whether to hide secrets in the message (default: true)
215
220
  # @return [nil]
216
221
  # @note Message display behavior depends on the message_level:
217
- # - +:data+ messages are displayed unless display level is +:error+
218
- # - +:info+ messages are only displayed when display level is +:info+
219
- # - +:error+ messages are always displayed on stderr
222
+ # - `:data` messages are displayed unless display level is `:error`
223
+ # - `:info` messages are only displayed when display level is `:info`
224
+ # - `:error` messages are always displayed on `stderr`
220
225
  def display_message(message_level, message, hide_secrets: true)
221
226
  message = SecretHider.instance.hide_secrets_in_string(message) if hide_secrets && message.is_a?(String) && hide_secrets?
222
227
  case message_level
@@ -291,14 +296,18 @@ module Aspera
291
296
  @options[:image].symbolize_keys
292
297
  end
293
298
 
294
- # @return [Array<String>] all fields of all objects in list of objects
299
+ # Compute the list of all fields for all provided objects
300
+ # @param data [Array<Hash>] objects
301
+ # @return [Array<String>] All fields of all objects in list of objects
295
302
  def all_fields(data)
296
- data.each_with_object({}) { |v, m| v.each_key { |c| m[c] = true } }.keys
303
+ data.flat_map(&:keys).uniq
297
304
  end
298
305
 
299
- # @return [Array<String>] the list of fields to display
300
- # @param data [Array<Hash>] data to display
301
- # @param default [Array<String>, Proc] list of fields to display by default (may contain special values)
306
+ # Given the list of objects (with all fields) and a default filter, including `DEF`, `ALL` and `-`,
307
+ # expand and compute the actual list of fields to display.
308
+ # @param data [Array<Hash>] Data to display
309
+ # @param default [Array<String>, Proc] List of fields to display by default (may contain special values)
310
+ # @return [Array<String>] List of fields to display
302
311
  def compute_fields(data, default)
303
312
  Log.log.debug { "compute_fields: data:#{data.class} default:#{default.class} #{default}" }
304
313
  Log.dump(:compute_fields_default, default, level: :trace1)
@@ -355,8 +364,9 @@ module Aspera
355
364
  return data.map { |i| i.slice(*selected_fields) }
356
365
  end
357
366
 
358
- # filter the list of items on the select option
359
- # @param data [Array<Hash>] list of items
367
+ # Filter the list of items on the select option
368
+ # @param data [Array<Hash>] List of items
369
+ # @return [nil]
360
370
  def filter_columns_on_select(data)
361
371
  case @options[:select]
362
372
  when Proc
@@ -368,12 +378,14 @@ module Aspera
368
378
  when Hash
369
379
  @options[:select].each { |k, v| data.select! { |i| i[k].eql?(v) } }
370
380
  end
381
+ nil
371
382
  end
372
383
 
373
384
  # Displays a list of objects
374
385
  # @param object_array [Array<Hash>] Array of hash
375
386
  # @param fields [Array<String>] List of column names
376
387
  # @param single [Boolean] Contains a single object to display
388
+ # @return [nil]
377
389
  def display_table(object_array, fields, single: false)
378
390
  Aspera.assert_array_all(object_array, Hash)
379
391
  Aspera.assert_array_all(fields, String)
@@ -19,7 +19,7 @@ module Aspera
19
19
  def check_gem_version
20
20
  latest_version =
21
21
  begin
22
- Rest.new(base_url: 'https://rubygems.org/api/v1').read("versions/#{Info::GEM_NAME}/latest.json")['version']
22
+ Rest::Client.new(base_url: 'https://rubygems.org/api/v1').read("versions/#{Info::GEM_NAME}/latest.json")['version']
23
23
  rescue StandardError
24
24
  Log.log.warn('Could not retrieve latest gem version on rubygems.')
25
25
  '0'
@@ -6,6 +6,7 @@ require 'aspera/log'
6
6
  require 'aspera/ssh'
7
7
  require 'aspera/assert'
8
8
  require 'aspera/cli/info'
9
+ require 'aspera/cli/terminal_formatter'
9
10
  require 'net/ssh'
10
11
  require 'openssl'
11
12
 
@@ -26,7 +27,7 @@ module Aspera
26
27
  ]
27
28
  },
28
29
  {
29
- exception: Aspera::RestCallError,
30
+ exception: Aspera::Rest::CallError,
30
31
  match: /Signature has expired/,
31
32
  remediation: [
32
33
  'There is too much time difference between your computer and the server',
@@ -70,7 +71,7 @@ module Aspera
70
71
  ]
71
72
  },
72
73
  {
73
- exception: Aspera::RestCallError,
74
+ exception: Aspera::Rest::CallError,
74
75
  match: /Invalid subject\./,
75
76
  remediation: [
76
77
  'It seems that this user name is not registered on the server',
@@ -102,7 +103,7 @@ module Aspera
102
103
  ]
103
104
  },
104
105
  {
105
- exception: Aspera::RestCallError,
106
+ exception: Aspera::Rest::CallError,
106
107
  match: /Server is not configured for this request/,
107
108
  remediation: [
108
109
  'Transfer user shall have those parameters in aspera.conf set to: token',
@@ -110,14 +111,14 @@ module Aspera
110
111
  ]
111
112
  },
112
113
  {
113
- exception: Aspera::RestCallError,
114
+ exception: Aspera::Rest::CallError,
114
115
  match: /invalid_grant/,
115
116
  remediation: [
116
117
  'Check your public key in your AoC user profile.'
117
118
  ]
118
119
  },
119
120
  {
120
- exception: Aspera::RestCallError,
121
+ exception: Aspera::Rest::CallError,
121
122
  match: /Please configure ACLs for this URI/,
122
123
  remediation: [
123
124
  'server must have: asnodeadmin -mu <node user> --acl-add=internal --internal'
@@ -145,7 +146,7 @@ module Aspera
145
146
  else Aspera.error_unexpected_value(m) { 'hint match' }
146
147
  end
147
148
  hint[:remediation].each do |r|
148
- Log.log.info { "#{'HINT:'.bg_green.gray.blink.freeze} #{r}" }
149
+ Log.log.info { "#{TerminalFormatter.hint} #{r}" }
149
150
  end
150
151
  end
151
152
  end
@@ -46,21 +46,21 @@ module Aspera
46
46
  attr_accessor :insecure, :warn_insecure
47
47
  attr_reader :ignore_cert_host_port, :http_options
48
48
 
49
- # Bind all HTTP options to this instance using set_handler.
49
+ # Bind all HTTP options to this instance using `on_set`.
50
50
  # Called from Config#initialize immediately after Http.new.
51
51
  # @param options [Aspera::Cli::Parser]
52
52
  # @return [nil]
53
53
  def bind_options(options)
54
- options.set_handler(:insecure, object: self, method: :insecure)
55
- options.set_handler(:ignore_certificate, object: self, method: :ignore_cert_host_port)
56
- options.set_handler(:warn_insecure, object: self, method: :warn_insecure)
57
- options.set_handler(:cert_stores, object: self, method: :trusted_cert_locations)
58
- options.set_handler(:http_options, object: self, method: :http_options)
59
- options.set_handler(:http_proxy, object: self, method: :http_proxy)
54
+ options.on_set(:insecure, method(:insecure=))
55
+ options.on_set(:ignore_certificate, method(:ignore_cert_host_port=))
56
+ options.on_set(:warn_insecure, method(:warn_insecure=))
57
+ options.on_set(:cert_stores, method(:trusted_cert_locations=))
58
+ options.on_set(:http_options, method(:http_options=))
59
+ options.on_set(:http_proxy, method(:http_proxy=))
60
60
  end
61
61
 
62
62
  # Setter for http_options: dispatch each key to its target singleton immediately.
63
- # Keys matching RestParameters setters go to RestParameters, 'ssl_options' goes to SSL,
63
+ # Keys matching Rest::Parameters setters go to Rest::Parameters, 'ssl_options' goes to SSL,
64
64
  # keys matching OAuth::Factory.instance.parameters go to OAuth, and the rest are kept
65
65
  # in @http_options for Net::HTTP session configuration in update_session.
66
66
  # This runs on every assignment (JSON hash, dotted notation, preset merge) so timing
@@ -72,8 +72,8 @@ module Aspera
72
72
  kept = {}
73
73
  new_options.each do |k, v|
74
74
  method = "#{k}=".to_sym
75
- if RestParameters.instance.respond_to?(method)
76
- RestParameters.instance.send(method, v)
75
+ if Rest::Parameters.instance.respond_to?(method)
76
+ Rest::Parameters.instance.send(method, v)
77
77
  elsif k.to_s.eql?('ssl_options')
78
78
  Aspera::SSL.option_list = v
79
79
  elsif OAuth::Factory.instance.parameters.key?(k.to_sym)
@@ -90,10 +90,6 @@ module Aspera
90
90
  # Proxy
91
91
  # ------------------------------------------------------------------
92
92
 
93
- def http_proxy
94
- ENV['http_proxy']
95
- end
96
-
97
93
  def http_proxy=(value)
98
94
  URI.parse(value)
99
95
  ENV['http_proxy'] = value
@@ -103,11 +99,12 @@ module Aspera
103
99
  # Per-URL certificate ignore list
104
100
  # ------------------------------------------------------------------
105
101
 
102
+ # @param url_list [Array<String>, nil] URLs for which certificate is not validated
106
103
  def ignore_cert_host_port=(url_list)
107
- url_list.each do |url|
104
+ @ignore_cert_host_port = (url_list || []).map do |url|
108
105
  uri = URI.parse(url)
109
106
  Aspera.assert(uri.scheme.eql?('https')) { "Expecting https scheme: #{url}" }
110
- @ignore_cert_host_port.push([uri.host, uri.port].freeze)
107
+ [uri.host, uri.port].freeze
111
108
  end
112
109
  end
113
110
 
@@ -134,13 +131,16 @@ module Aspera
134
131
  # Add files, folders or the default OS locations to the cert store.
135
132
  # @param path_list [Array<String>] list of file/folder paths to add to the certificate store
136
133
  # @return [nil]
134
+ # Replace the certificate store with the given locations
135
+ # @param path_list [Array<String>] files or folders, or `DEF` for system default; empty: system default
137
136
  def trusted_cert_locations=(path_list)
138
137
  Aspera.assert_type(path_list, Array) { 'cert locations' }
139
- if @certificate_store.nil?
140
- Log.log.debug('Creating SSL Cert store')
141
- @certificate_store = OpenSSL::X509::Store.new
142
- @certificate_paths = []
143
- end
138
+ # Empty: lazily initialized with system default
139
+ @certificate_store = @certificate_paths = nil
140
+ return if path_list.empty?
141
+ Log.log.debug('Creating SSL Cert store')
142
+ @certificate_store = OpenSSL::X509::Store.new
143
+ @certificate_paths = []
144
144
  path_list.each do |path|
145
145
  Aspera.assert_type(path, String) { 'Expecting a String for certificate location' }
146
146
  paths_to_add = [path]
@@ -17,6 +17,9 @@ module Aspera
17
17
  RUBY_FUTURE_MINIMUM_VERSION = '3.2'
18
18
  # Version with which this version of CLI was tested
19
19
  SDK_VERSION = '1.1.9'
20
+ # RubyInstaller version packaged in the Windows installer zip (release tag without `RubyInstaller-` prefix)
21
+ # https://github.com/oneclick/rubyinstaller2/releases
22
+ WINDOWS_RUBY_INSTALLER_VERSION = '4.0.7-1'
20
23
  end
21
24
  end
22
25
  end