aspera-cli 4.25.2 → 4.25.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.
data/CONTRIBUTING.md CHANGED
@@ -110,13 +110,14 @@ A few macros and environment variables control certain aspects of the build:
110
110
  | `ASPERA_CLI_TEST_CONF_URL` | URL for configuration file with secrets for tests. |
111
111
  | `ASPERA_CLI_DOC_CHECK_LINKS`| Check links still exist during doc generation. |
112
112
  | `LOG_LEVEL` | Change log level in `rake` tasks. |
113
+ | `LOG_SECRETS` | Change log secrets in `rake` tasks. |
113
114
  | `ENABLE_COVERAGE` | Enable test coverage analysis when set. |
114
115
  | `SIGNING_KEY` | Path to the signing key used to build the gem file. |
115
116
  | `SIGNING_KEY_PEM` | PEM of signing key. |
116
117
 
117
118
  These can be set either as environment variables or directly on the `rake` command line.
118
119
 
119
- Setting `SIGNING_KEY_PEM` creates file `$HOME/.gem/signing_key.pem` and sets `SIGNING_KEY`.
120
+ Setting `SIGNING_KEY_PEM` creates file `$HOME/.gem/signing_key.pem` and sets `SIGNING_KEY` to that path.
120
121
 
121
122
  > [!NOTE]
122
123
  > Environment variables `ASPERA_CLI_*` are typically set in the user’s shell profile for development.
@@ -153,6 +154,12 @@ To check URLs during documentation generation, set the environment variable: `AS
153
154
 
154
155
  To debug documentation generation, set the environment variable: `ASPERA_CLI_DOC_DEBUG=debug`.
155
156
 
157
+ To generate documentation:
158
+
159
+ ```bash
160
+ rake doc:build
161
+ ```
162
+
156
163
  ## Test Environment
157
164
 
158
165
  Refer to <tests/README.md>.
@@ -192,7 +199,7 @@ Update with:
192
199
  bundle exec rake tools:grpc
193
200
  ```
194
201
 
195
- It downloads the latest `proto` file and then compiles it.
202
+ It downloads the latest `proto` file and then compiles it into ruby sources included in the repo.
196
203
 
197
204
  ## Container image build
198
205
 
@@ -212,7 +219,8 @@ bundle exec rake -T ^binary:
212
219
 
213
220
  ### Branching Strategy
214
221
 
215
- This project uses a single `main` branch for development. During the development cycle, the version in `lib/aspera/cli/version.rb` uses a `.pre` suffix (e.g., `x.y.z.pre`) to indicate a pre-release state.
222
+ This project uses a single `main` branch for development.
223
+ During the development cycle, the version in `lib/aspera/cli/version.rb` uses a `.pre` suffix (e.g., `x.y.z.pre`) to indicate a pre-release state.
216
224
 
217
225
  Feature development and bug fixes can be done either:
218
226
 
@@ -229,10 +237,10 @@ When preparing for a new release, do the following:
229
237
  bundle exec rake test:run
230
238
  ```
231
239
 
232
- - Verify that the container builds successfully (using the beta version):
240
+ - Verify that the container builds successfully (using the local gem file):
233
241
 
234
242
  ```bash
235
- bundle exec rake container:build
243
+ bundle exec rake container:build'[local]'
236
244
  bundle exec rake container:test
237
245
  ```
238
246
 
@@ -252,16 +260,17 @@ To create a release:
252
260
  The workflow automatically:
253
261
 
254
262
  1. Updates `version.rb` with the release version
255
- 2. Rebuilds documentation (PDF manual, README)
263
+ 2. Rebuilds documentation (PDF manual, Markdown README)
256
264
  3. Commits the changes
257
265
  4. Creates and pushes the release tag
258
266
  5. Triggers the `deploy` workflow to publish to [rubygems.org](https://rubygems.org/gems/aspera-cli)
259
267
  6. Updates `version.rb` to the next development version with `.pre` suffix
260
- 7. Commits and pushes the version bump
268
+ 7. Commits and pushes the version bump in main branch.
261
269
 
262
270
  ### Manual Release Process (Alternative)
263
271
 
264
- If needed, releases can still be done manually:
272
+ If needed, releases can still be done manually.
273
+ Basically, follow the same procedure as in the GitHub action:
265
274
 
266
275
  - Update the version in `lib/aspera/cli/version.rb` (remove `.pre` suffix)
267
276
 
data/README.md CHANGED
@@ -9,17 +9,20 @@
9
9
  Use it from the terminal or in scripts to:
10
10
 
11
11
  - Drive **Aspera on Cloud**, **Faspex**, **Shares**, **Node**, **Console**, **Orchestrator**, and **High-Speed Transfer Server**
12
- - Call REST APIs and run high-speed transfers (FASP)
12
+ - Call REST APIs and run high-speed transfers (**FASP**)
13
13
  - Automate workflows with config, presets, and scripting
14
14
 
15
15
  ## Documentation
16
16
 
17
+ Choose what best suits you:
18
+
17
19
  | Resource | Link |
18
- |----------|------|
20
+ | -------- | ---- |
19
21
  | **Online manual** | [docs/README.md](docs/README.md) |
20
22
  | **PDF manual** | In [releases](https://github.com/IBM/aspera-cli/releases) |
21
23
  | **RubyGems** | [rubygems.org/gems/aspera-cli](https://rubygems.org/gems/aspera-cli) |
22
24
  | **RubyDoc** | [rubydoc.info/gems/aspera-cli](https://www.rubydoc.info/gems/aspera-cli) |
25
+ | **Docsify** | [online](https://docsify-this.net/?basePath=https://raw.githubusercontent.com/IBM/aspera-cli/main/docs&homepage=README.md&sidebar=true&browser-tab-title=Aspera%20CLI%20Manual&hide-credits=true&maxLevel=4&externalLinkTarget=_blank&image-captions=true&dark-mode=auto) |
23
26
 
24
27
  ## Install
25
28
 
@@ -30,7 +33,7 @@ gem install aspera-cli
30
33
  ascli config transferd install
31
34
  ```
32
35
 
33
- The second command installs the FASP transfer engine (`ascp`).
36
+ The second command installs the **FASP** transfer engine (`ascp`).
34
37
  For other install methods (single executable, Docker, Chocolatey, Homebrew), see the [user manual](docs/README.md#installation).
35
38
 
36
39
  **Quick check:**
@@ -142,11 +142,14 @@ module Aspera
142
142
  }
143
143
  end
144
144
 
145
- # Call block with same query using paging and response information.
146
- # Block must return an Array with data and http response
147
- # @return [Hash] {items: , total: }
148
- def call_paging(query: nil, formatter: nil)
149
- query = {} if query.nil?
145
+ # Call `block` with same query using paging and response information.
146
+ # Block must return a 2 element `Array` with data and http response
147
+ # @param query [Hash] Additionnal query parameters
148
+ # @param progress [nil, Object] Uses methods: `long_operation_running` and `long_operation_terminated`
149
+ # @return [Hash] Items and total number of items
150
+ # @option return [Array<Hash>] :items The list of items
151
+ # @option return [Integer] :total The total number of items
152
+ def call_paging(query: {}, progress: nil)
150
153
  Aspera.assert_type(query, Hash){'query'}
151
154
  Aspera.assert(block_given?)
152
155
  # set default large page if user does not specify own parameters. AoC Caps to 1000 anyway
@@ -174,9 +177,9 @@ module Aspera
174
177
  break if !max_items.nil? && item_list.count >= max_items
175
178
  break if !max_pages.nil? && page_count >= max_pages
176
179
  break if total_count&.<=(item_list.count)
177
- formatter&.long_operation_running("#{item_list.count} / #{total_count}") unless total_count.eql?(item_list.count.to_s)
180
+ progress&.long_operation_running("#{item_list.count} / #{total_count}") unless total_count.eql?(item_list.count.to_s)
178
181
  end
179
- formatter&.long_operation_terminated
182
+ progress&.long_operation_terminated
180
183
  item_list = item_list[0..max_items - 1] if !max_items.nil? && item_list.count > max_items
181
184
  return {items: item_list, total: total_count}
182
185
  end
@@ -229,7 +232,8 @@ module Aspera
229
232
  username: nil,
230
233
  password: nil,
231
234
  workspace: nil,
232
- secret_finder: nil
235
+ secret_finder: nil,
236
+ progress_disp: nil
233
237
  )
234
238
  # Test here because link may set url
235
239
  Aspera.assert(url, 'Missing mandatory option: url', type: ParameterError)
@@ -240,6 +244,7 @@ module Aspera
240
244
  # key: access key
241
245
  # value: associated secret
242
246
  @secret_finder = secret_finder
247
+ @progress_disp = progress_disp
243
248
  @workspace_name = workspace
244
249
  @cache_user_info = nil
245
250
  @cache_url_token_info = nil
@@ -299,10 +304,12 @@ module Aspera
299
304
  )
300
305
  end
301
306
 
302
- # read using the query and paging
307
+ # Read using the query and paging
308
+ # @param subpath [String] Entity path
309
+ # @param query [nil, Hash] Additional query
303
310
  # @return [Hash] {items: , total: }
304
- def read_with_paging(subpath, query = nil, formatter: nil)
305
- return self.class.call_paging(query: query, formatter: formatter) do |paged_query|
311
+ def read_with_paging(subpath, query = nil)
312
+ return self.class.call_paging(query: query, progress: @progress_disp) do |paged_query|
306
313
  read(subpath, query: paged_query, ret: :both)
307
314
  end
308
315
  end
@@ -710,7 +717,7 @@ module Aspera
710
717
  # (optional). The name of the folder to be displayed to the destination user.
711
718
  # Use it if its value is different from the "share_as" field.
712
719
  event_creation['link_name'] = app_info[:opt_link_name] unless app_info[:opt_link_name].nil?
713
- create('events', event_creation)
720
+ create('events', event_creation, query: {admin: true})
714
721
  end
715
722
  end
716
723
  end
@@ -60,19 +60,32 @@ module Aspera
60
60
  PATH_AUTH = 'auth'
61
61
  PATH_API_V5 = 'api/v5'
62
62
  PATH_HEALTH = 'configuration/ping'
63
- private_constant :PATH_API_V5,
64
- :PATH_HEALTH,
65
- :PATH_AUTH
63
+ private_constant :PATH_AUTH,
64
+ :PATH_API_V5,
65
+ :PATH_HEALTH
66
66
  RECIPIENT_TYPES = %w[user workgroup external_user distribution_list shared_inbox].freeze
67
67
  PACKAGE_TERMINATED = %w[completed failed].freeze
68
68
  # list of supported mailbox types (to list packages)
69
- API_LIST_MAILBOX_TYPES = %w[inbox inbox_history inbox_all inbox_all_history outbox outbox_history pending pending_history all].freeze
69
+ SENT_MAILBOX_TYPES = %w[outbox outbox_history].freeze
70
+ API_LIST_MAILBOX_TYPES = (%w[inbox inbox_history inbox_all inbox_all_history pending pending_history all] + SENT_MAILBOX_TYPES).freeze
70
71
  # PACKAGE_SEND_FROM_REMOTE_SOURCE = 'remote_source'
71
72
  # Faspex API v5: get transfer spec for connect
72
73
  TRANSFER_CONNECT = 'connect'
73
74
  ADMIN_RESOURCES = %i[
74
- accounts distribution_lists contacts jobs workgroups shared_inboxes nodes oauth_clients registrations saml_configs
75
- metadata_profiles email_notifications alternate_addresses webhooks
75
+ accounts
76
+ distribution_lists
77
+ contacts
78
+ jobs
79
+ workgroups
80
+ shared_inboxes
81
+ nodes
82
+ oauth_clients
83
+ registrations
84
+ saml_configs
85
+ metadata_profiles
86
+ email_notifications
87
+ alternate_addresses
88
+ webhooks
76
89
  ].freeze
77
90
  # states for jobs not in final state
78
91
  JOB_RUNNING = %w[queued working].freeze
@@ -114,6 +127,12 @@ module Aspera
114
127
  def public_link?(url)
115
128
  url.include?('?context=')
116
129
  end
130
+
131
+ # Depending on box, the package files are either: `received` or `sent`
132
+ # @return [:sent, :received] the type of mailbox
133
+ def box_type(box)
134
+ SENT_MAILBOX_TYPES.include?(box) || box == 'ALL' ? :sent : :received
135
+ end
117
136
  end
118
137
  attr_reader :pub_link_context
119
138
 
@@ -65,7 +65,7 @@ module Aspera
65
65
  # Adds cache control header, as globally specified to read request
66
66
  # Use like this: read(...,**cache_control)
67
67
  def cache_control
68
- headers = {'Accept' => Rest::MIME_JSON}
68
+ headers = {'Accept' => Mime::JSON}
69
69
  headers[HEADER_X_CACHE_CONTROL] = 'no-cache' unless use_node_cache
70
70
  {headers: headers}
71
71
  end
@@ -308,7 +308,9 @@ module Aspera
308
308
  # @param top_file_id [String] id initial file id
309
309
  # @param path [String] file or folder path (end with "/" is like setting process_last_link)
310
310
  # @param process_last_link [Boolean] if true, follow the last link
311
- # @return [Hash] {.api,.file_id}
311
+ # @return [Hash] Result data
312
+ # @option return [Aspera::Rest] :api REST client instance
313
+ # @option return [String] :file_id File identifier
312
314
  def resolve_api_fid(top_file_id, path, process_last_link = false)
313
315
  Aspera.assert_type(top_file_id, String)
314
316
  Aspera.assert_type(path, String)
data/lib/aspera/assert.rb CHANGED
@@ -93,7 +93,7 @@ module Aspera
93
93
  # The value is not one of the expected values
94
94
  # @param value [Object] The wrong value
95
95
  # @param type [Exception,Symbol] Exception to raise, or Symbol for Log.log
96
- # @param block [Proc] Additional description in front of message
96
+ # @param &block [Proc] Additional description in front of message
97
97
  def error_unexpected_value(value, type: InternalError)
98
98
  report_error(type, "#{"#{yield}: " if block_given?}unexpected value: #{value.inspect}")
99
99
  end
@@ -115,6 +115,13 @@ module Aspera
115
115
  remediation: [
116
116
  'Check your public key in your AoC user profile.'
117
117
  ]
118
+ },
119
+ {
120
+ exception: Aspera::RestCallError,
121
+ match: /Please configure ACLs for this URI/,
122
+ remediation: [
123
+ 'server must have: asnodeadmin -mu <node user> --acl-add=internal --internal'
124
+ ]
118
125
  }
119
126
  ]
120
127
  private_constant :ERROR_HINTS
@@ -12,6 +12,37 @@ require 'optparse'
12
12
 
13
13
  module Aspera
14
14
  module Cli
15
+ module BoolValue
16
+ # boolean options are set to true/false from the following values
17
+ YES_SYM = :yes
18
+ NO_SYM = :no
19
+ FALSE_VALUES = [NO_SYM, false].freeze
20
+ TRUE_VALUES = [YES_SYM, true].freeze
21
+ private_constant :YES_SYM, :NO_SYM, :FALSE_VALUES, :TRUE_VALUES
22
+ # Boolean values
23
+ # @return [Array<true, false, :yes, :no>]
24
+ ALL = (TRUE_VALUES + FALSE_VALUES).freeze
25
+ TYPES = [FalseClass, TrueClass].freeze
26
+ SYMBOLS = [NO_SYM, YES_SYM].freeze
27
+ # @return `true` if value is a value for `true` in ALL
28
+ def true?(enum)
29
+ Aspera.assert_values(enum, ALL){'boolean'}
30
+ return TRUE_VALUES.include?(enum)
31
+ end
32
+
33
+ # @return [:yes, :no]
34
+ def to_sym(enum)
35
+ Aspera.assert_values(enum, ALL){'boolean'}
36
+ return TRUE_VALUES.include?(enum) ? YES_SYM : NO_SYM
37
+ end
38
+
39
+ # @return `true` if value is a value for `true` or `false` in ALL
40
+ def symbol?(sym)
41
+ return ALL.include?(sym)
42
+ end
43
+ module_function :true?, :to_sym, :symbol?
44
+ end
45
+
15
46
  # Constants to be used as parameter `allowed:` for `OptionValue`
16
47
  module Allowed
17
48
  # This option can be set to a single string or array, multiple times, and gives Array of String
@@ -20,7 +51,7 @@ module Aspera
20
51
  TYPES_SYMBOL_ARRAY = [Array, Symbol].freeze
21
52
  # Value will be coerced to int
22
53
  TYPES_INTEGER = [Integer].freeze
23
- TYPES_BOOLEAN = [FalseClass, TrueClass].freeze
54
+ TYPES_BOOLEAN = BoolValue::TYPES
24
55
  # no value at all, it's a switch
25
56
  TYPES_NONE = [].freeze
26
57
  TYPES_ENUM = [Symbol].freeze
@@ -74,7 +105,7 @@ module Aspera
74
105
  @values = allowed[Allowed::TYPES_SYMBOL_ARRAY.length..-1]
75
106
  elsif allowed.all?(Class)
76
107
  @types = allowed
77
- @values = Manager::BOOLEAN_VALUES if allowed.eql?(Allowed::TYPES_BOOLEAN)
108
+ @values = BoolValue::ALL if allowed.eql?(Allowed::TYPES_BOOLEAN)
78
109
  # Default value for array
79
110
  @object ||= [] if @types.first.eql?(Array) && !@types.include?(NilClass)
80
111
  @object ||= {} if @types.first.eql?(Hash) && !@types.include?(NilClass)
@@ -110,7 +141,7 @@ module Aspera
110
141
  Aspera.assert(!@deprecation, type: warn){"Option #{@option} is deprecated: #{@deprecation}"}
111
142
  new_value = ExtendedValue.instance.evaluate(value, context: "option: #{@option}", allowed: @types)
112
143
  Log.log.trace1{"#{where}: #{@option} <- (#{new_value.class})#{new_value}"}
113
- new_value = Manager.enum_to_bool(new_value) if @types.eql?(Allowed::TYPES_BOOLEAN)
144
+ new_value = BoolValue.true?(new_value) if @types.eql?(Allowed::TYPES_BOOLEAN)
114
145
  new_value = Integer(new_value) if @types.eql?(Allowed::TYPES_INTEGER)
115
146
  new_value = [new_value] if @types.eql?(Allowed::TYPES_STRING_ARRAY) && new_value.is_a?(String)
116
147
  # Setting a Hash to null set an empty hash
@@ -142,20 +173,7 @@ module Aspera
142
173
  # arguments options start with '-', others are commands
143
174
  # resolves on extended value syntax
144
175
  class Manager
145
- BOOLEAN_SIMPLE = %i[no yes].freeze
146
176
  class << self
147
- # @return `true` if value is a value for `true` in BOOLEAN_VALUES
148
- def enum_to_bool(enum)
149
- Aspera.assert_values(enum, BOOLEAN_VALUES){'boolean'}
150
- return TRUE_VALUES.include?(enum)
151
- end
152
-
153
- # @return :yes ot :no
154
- def enum_to_yes_no(enum)
155
- Aspera.assert_values(enum, BOOLEAN_VALUES){'boolean'}
156
- return TRUE_VALUES.include?(enum) ? BOOL_YES : BOOL_NO
157
- end
158
-
159
177
  # Find shortened string value in allowed symbol list
160
178
  def get_from_list(short_value, descr, allowed_values)
161
179
  Aspera.assert_type(short_value, String)
@@ -165,7 +183,7 @@ module Aspera
165
183
  matching = allowed_values.select{ |i| i.to_s.start_with?(short_value)}
166
184
  Aspera.assert(!matching.empty?, multi_choice_assert_msg("unknown value for #{descr}: #{short_value}", allowed_values), type: BadArgument)
167
185
  Aspera.assert(matching.length.eql?(1), multi_choice_assert_msg("ambiguous shortcut for #{descr}: #{short_value}", matching), type: BadArgument)
168
- return enum_to_bool(matching.first) if allowed_values.eql?(BOOLEAN_VALUES)
186
+ return BoolValue.true?(matching.first) if allowed_values.eql?(BoolValue::ALL)
169
187
  return matching.first
170
188
  end
171
189
 
@@ -279,11 +297,11 @@ module Aspera
279
297
  case option_attrs.types
280
298
  when Allowed::TYPES_ENUM, Allowed::TYPES_BOOLEAN
281
299
  # This option value must be a symbol (or array of symbols)
282
- set_option(option_symbol, Manager.enum_to_bool(default), where: 'default') if option_attrs.values.eql?(BOOLEAN_VALUES) && !default.nil?
300
+ set_option(option_symbol, BoolValue.true?(default), where: 'default') if option_attrs.values.eql?(BoolValue::ALL) && !default.nil?
283
301
  value = get_option(option_symbol)
284
302
  help_values =
285
303
  if option_attrs.types.eql?(Allowed::TYPES_BOOLEAN)
286
- highlight_current_in_list(BOOLEAN_SIMPLE, self.class.enum_to_yes_no(value))
304
+ highlight_current_in_list(BoolValue::SYMBOLS, BoolValue.to_sym(value))
287
305
  else
288
306
  highlight_current_in_list(option_attrs.values, value)
289
307
  end
@@ -636,12 +654,6 @@ module Aspera
636
654
  unprocessed_options.delete(k)
637
655
  end
638
656
  end
639
- # boolean options are set to true/false from the following values
640
- BOOL_YES = BOOLEAN_SIMPLE.last
641
- BOOL_NO = BOOLEAN_SIMPLE.first
642
- FALSE_VALUES = [BOOL_NO, false].freeze
643
- TRUE_VALUES = [BOOL_YES, true].freeze
644
- BOOLEAN_VALUES = (TRUE_VALUES + FALSE_VALUES).freeze
645
657
 
646
658
  # Option name separator on command line, e.g. in --option-blah, third "-"
647
659
  OPTION_SEP_LINE = '-'
@@ -655,7 +667,7 @@ module Aspera
655
667
  OPTIONS_STOP = '--'
656
668
  SOURCE_USER = 'cmdline' # cspell:disable-line
657
669
 
658
- private_constant :BOOL_YES, :BOOL_NO, :FALSE_VALUES, :TRUE_VALUES, :OPTION_SEP_LINE, :OPTION_SEP_SYMBOL, :OPTION_VALUE_SEPARATOR, :OPTION_PREFIX, :OPTIONS_STOP, :SOURCE_USER
670
+ private_constant :OPTION_SEP_LINE, :OPTION_SEP_SYMBOL, :OPTION_VALUE_SEPARATOR, :OPTION_PREFIX, :OPTIONS_STOP, :SOURCE_USER
659
671
  end
660
672
  end
661
673
  end