aspera-cli 4.25.1 → 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.
Files changed (54) hide show
  1. checksums.yaml +4 -4
  2. checksums.yaml.gz.sig +0 -0
  3. data/CHANGELOG.md +456 -405
  4. data/CONTRIBUTING.md +22 -18
  5. data/README.md +33 -9741
  6. data/bin/asession +111 -88
  7. data/lib/aspera/agent/connect.rb +1 -1
  8. data/lib/aspera/agent/desktop.rb +1 -1
  9. data/lib/aspera/agent/direct.rb +19 -18
  10. data/lib/aspera/agent/node.rb +1 -1
  11. data/lib/aspera/api/aoc.rb +44 -20
  12. data/lib/aspera/api/faspex.rb +25 -6
  13. data/lib/aspera/api/node.rb +20 -16
  14. data/lib/aspera/ascp/installation.rb +32 -51
  15. data/lib/aspera/assert.rb +2 -2
  16. data/lib/aspera/cli/extended_value.rb +1 -0
  17. data/lib/aspera/cli/formatter.rb +0 -4
  18. data/lib/aspera/cli/hints.rb +18 -4
  19. data/lib/aspera/cli/main.rb +3 -6
  20. data/lib/aspera/cli/manager.rb +46 -30
  21. data/lib/aspera/cli/plugins/aoc.rb +155 -131
  22. data/lib/aspera/cli/plugins/base.rb +15 -18
  23. data/lib/aspera/cli/plugins/config.rb +50 -87
  24. data/lib/aspera/cli/plugins/factory.rb +2 -2
  25. data/lib/aspera/cli/plugins/faspex.rb +4 -4
  26. data/lib/aspera/cli/plugins/faspex5.rb +74 -76
  27. data/lib/aspera/cli/plugins/node.rb +3 -5
  28. data/lib/aspera/cli/plugins/oauth.rb +26 -25
  29. data/lib/aspera/cli/plugins/preview.rb +9 -14
  30. data/lib/aspera/cli/plugins/shares.rb +15 -7
  31. data/lib/aspera/cli/transfer_agent.rb +2 -2
  32. data/lib/aspera/cli/version.rb +1 -1
  33. data/lib/aspera/colors.rb +7 -0
  34. data/lib/aspera/environment.rb +30 -16
  35. data/lib/aspera/faspex_gw.rb +6 -6
  36. data/lib/aspera/faspex_postproc.rb +20 -14
  37. data/lib/aspera/hash_ext.rb +8 -0
  38. data/lib/aspera/log.rb +15 -15
  39. data/lib/aspera/markdown.rb +22 -0
  40. data/lib/aspera/node_simulator.rb +1 -1
  41. data/lib/aspera/oauth/base.rb +2 -2
  42. data/lib/aspera/oauth/url_json.rb +2 -2
  43. data/lib/aspera/oauth/web.rb +1 -1
  44. data/lib/aspera/preview/generator.rb +9 -9
  45. data/lib/aspera/rest.rb +44 -37
  46. data/lib/aspera/rest_call_error.rb +16 -8
  47. data/lib/aspera/rest_error_analyzer.rb +38 -36
  48. data/lib/aspera/rest_errors_aspera.rb +19 -18
  49. data/lib/aspera/transfer/resumer.rb +2 -2
  50. data/lib/aspera/yaml.rb +49 -0
  51. data.tar.gz.sig +0 -0
  52. metadata +17 -3
  53. metadata.gz.sig +0 -0
  54. data/release_notes.md +0 -8
@@ -90,8 +90,8 @@ module Aspera
90
90
  Aspera::Preview::Options::DESCRIPTIONS.each do |opt|
91
91
  values = if opt.key?(:values)
92
92
  opt[:values]
93
- elsif Cli::Manager::BOOLEAN_SIMPLE.include?(opt[:default])
94
- Allowed::TYPES_BOOLEAN
93
+ elsif BoolValue.symbol?(opt[:default])
94
+ BoolValue::TYPES
95
95
  end
96
96
  options.declare(opt[:name], opt[:description].capitalize, allowed: values, handler: {o: @gen_options, m: opt[:name]}, default: opt[:default])
97
97
  end
@@ -106,17 +106,12 @@ module Aspera
106
106
  Log.log.debug{"tmpdir: #{@tmp_folder}"}
107
107
  end
108
108
 
109
- # /files/id/files is normally cached in redis, but we can discard the cache
109
+ # /files/id/files is normally cached in Redis, but we can discard the cache
110
110
  # but /files/id is not cached
111
111
  def get_folder_entries(file_id, request_args = nil)
112
- headers = {'Accept' => Rest::MIME_JSON}
112
+ headers = {'Accept' => Mime::JSON}
113
113
  headers['X-Aspera-Cache-Control'] = 'no-cache' if @option_folder_reset_cache.eql?(:header)
114
- return @api_node.call(
115
- operation: 'GET',
116
- subpath: "files/#{file_id}/files",
117
- headers: headers,
118
- query: request_args
119
- )
114
+ return @api_node.read("files/#{file_id}/files", request_args, headers: headers)
120
115
  end
121
116
 
122
117
  # old version based on folders
@@ -153,7 +148,7 @@ module Aspera
153
148
  end
154
149
  # log/persist periodically or last one
155
150
  next unless @periodic.trigger? || event.equal?(events.last)
156
- Log.log.info{"Processed event #{event['id']}"}
151
+ Log.log.debug{"Processed event #{event['id']}"}
157
152
  # save checkpoint to avoid losing processing in case of error
158
153
  if !iteration_persistency.nil?
159
154
  iteration_persistency.data[0] = event['id'].to_s
@@ -186,7 +181,7 @@ module Aspera
186
181
  end
187
182
  # log/persist periodically or last one
188
183
  next unless @periodic.trigger? || event.equal?(events.last)
189
- Log.log.info{"Processing event #{event['id']}"}
184
+ Log.log.debug{"Processing event #{event['id']}"}
190
185
  # save checkpoint to avoid losing processing in case of error
191
186
  if !iteration_persistency.nil?
192
187
  iteration_persistency.data[0] = event['id'].to_s
@@ -303,7 +298,7 @@ module Aspera
303
298
  # download original file to temp folder
304
299
  do_transfer(Transfer::Spec::DIRECTION_RECEIVE, entry['parent_file_id'], entry['name'], @tmp_folder)
305
300
  end
306
- Log.log.info{"source: #{entry['id']}: #{entry['path']}"}
301
+ Log.log.debug{"source: #{entry['id']}: #{entry['path']}"}
307
302
  gen_infos.each do |gen_info|
308
303
  gen_info[:generator].generate rescue nil
309
304
  end
@@ -335,7 +330,7 @@ module Aspera
335
330
  entry = entries_to_process.shift
336
331
  # process this entry only if it is within the top_path
337
332
  entry_path_with_slash = entry['path']
338
- Log.log.info{"processing entry #{entry_path_with_slash}"} if @periodic.trigger?
333
+ Log.log.debug{"processing entry #{entry_path_with_slash}"} if @periodic.trigger?
339
334
  entry_path_with_slash = "#{entry_path_with_slash}/" unless entry_path_with_slash.end_with?('/')
340
335
  if !top_path.nil? && !top_path.start_with?(entry_path_with_slash) && !entry_path_with_slash.start_with?(top_path)
341
336
  Log.log.debug{"#{entry['path']} folder (skip start)".bg_red}
@@ -17,20 +17,21 @@ module Aspera
17
17
  # @return [Hash] with version, ping, api
18
18
  def health_check(url)
19
19
  result = {}
20
+ # Get version from main page
20
21
  result[:version] =
21
22
  begin
22
23
  version = nil
23
24
  login_page = Rest
24
25
  .new(base_url: url, redirect_max: 2)
25
26
  .read('', headers: {'Accept'=>'text/html'})
27
+ raise 'not Shares' unless login_page.include?('aspera-Shares')
26
28
  if (m = login_page.match(/\(v([0-9a-f\.]+)\)/))
27
29
  version = m[1]
28
30
  if (m = login_page.match(/Patch level ([0-9]+)/))
29
- version = "#{result[:version]} #{m[0]}"
31
+ version = "#{version} #{m[0]}"
30
32
  end
31
33
  end
32
- raise 'no version' if version.nil?
33
- version
34
+ version.nil? ? 'no version' : version
34
35
  rescue => e
35
36
  e
36
37
  end
@@ -45,10 +46,15 @@ module Aspera
45
46
  end
46
47
  result[:api] =
47
48
  begin
48
- resp = Rest.new(base_url: url, redirect_max: 1).read("#{NODE_API_PATH}/app", exception: false, ret: :resp)
49
+ data, resp = Rest
50
+ .new(base_url: "#{url}/#{NODE_API_PATH}", redirect_max: 1)
51
+ .read('info', exception: false, ret: :both)
49
52
  # shall fail: shares requires auth, but we check error message
50
- raise 'not found' unless resp.code.to_s.eql?('401') && resp.body.eql?('{"error":{"user_message":"API user authentication failed"}}')
51
- 'available'
53
+ if resp.code.to_s.eql?('401') && data&.dig('error', 'user_message')&.include?('authentication failed')
54
+ 'available'
55
+ else
56
+ raise "not found (#{resp.code})"
57
+ end
52
58
  rescue => e
53
59
  e
54
60
  end
@@ -88,7 +94,7 @@ module Aspera
88
94
  SAML_IMPORT_MANDATORY = %w[id name_id].freeze
89
95
  SAML_IMPORT_ALLOWED = %w[email given_name surname].concat(SAML_IMPORT_MANDATORY).freeze
90
96
 
91
- ACTIONS = %i[health files admin].freeze
97
+ ACTIONS = %i[health info files admin].freeze
92
98
  # common to users and groups
93
99
  USR_GRP_SETTINGS = %i[transfer_settings app_authorizations share_permissions].freeze
94
100
 
@@ -111,6 +117,8 @@ module Aspera
111
117
  nagios.add_critical('API', health[:api].to_s)
112
118
  end
113
119
  Main.result_object_list(nagios.status_list)
120
+ when :info
121
+ return Main.result_single_object(basic_auth_api(NODE_API_PATH).read('info', headers: {'Content-Type'=>'application/json'}))
114
122
  when :files
115
123
  api_shares_node = basic_auth_api(NODE_API_PATH)
116
124
  repo_command = options.get_next_command(Node::COMMANDS_SHARES)
@@ -33,8 +33,8 @@ module Aspera
33
33
  :DEFAULT_TRANSFER_NOTIFY_TEMPLATE
34
34
 
35
35
  class << self
36
- # @return :success if all sessions statuses returned by "start" are success
37
- # else return the first error exception object
36
+ # @return [:success] if all sessions statuses returned by "start" are success
37
+ # @return [Exception] if one sessions statuses returned by "start" is failed
38
38
  def session_status(statuses)
39
39
  error_statuses = statuses.reject{ |i| i.eql?(:success)}
40
40
  return :success if error_statuses.empty?
@@ -4,6 +4,6 @@ module Aspera
4
4
  module Cli
5
5
  # For beta add extension : .beta1
6
6
  # For dev version add extension : .pre
7
- VERSION = '4.25.1'
7
+ VERSION = '4.25.3'
8
8
  end
9
9
  end
data/lib/aspera/colors.rb CHANGED
@@ -58,6 +58,13 @@ class String
58
58
  end
59
59
  end
60
60
 
61
+ # Applies the provided list of string decoration (colors).
62
+ # @param colors [Array<Symbol>] List of decorations.
63
+ # @return [String] Enhanced String.
64
+ def apply(*colors)
65
+ colors.reduce(self){ |s, c| s.public_send(c)}
66
+ end
67
+
61
68
  # Transform capitalized to snake case
62
69
  def capital_to_snake
63
70
  return gsub(/([a-z\d])([A-Z])/, '\1_\2')
@@ -58,8 +58,8 @@ module Aspera
58
58
  # @param code [String] Ruby code to execute
59
59
  # @param file [String] File name for error reporting
60
60
  # @param line [Integer] Line number for error reporting
61
- def secure_eval(code, file, line)
62
- Kernel.send('lave'.reverse, code, empty_binding, file, line)
61
+ def secure_eval(code, file, line, user_binding = nil)
62
+ Kernel.send('lave'.reverse, code, user_binding || empty_binding, file, line)
63
63
  end
64
64
 
65
65
  # Build argv for Process.spawn / Kernel.system (no shell)
@@ -74,26 +74,40 @@ module Aspera
74
74
  argv
75
75
  end
76
76
 
77
- # Execute a process securely (no shell)
78
- # mode:
79
- # :execute -> Kernel.system, return nil
80
- # :background -> Process.spawn, return pid
81
- # :capture -> Open3.capture3, return stdout
82
- # @param cmd [Array] Command and arguments
83
- # @param env [Hash, nil] Environment variables
84
- # @param mode [Symbol] Execution mode (see above)
85
- # @param kwargs [Hash] Additional arguments to underlying method, includes:
86
- # :exception [Boolean] for :capture mode, raise error if process fails
87
- # :close_others [Boolean] for :background mode
88
- # :env [Hash] for :execute mode
77
+ # like `Shellwords.shellescape`, but does not escape `=`
78
+ def shell_escape_pretty(str)
79
+ # Safe unquoted characters + '=' explicitly allowed
80
+ return str if str.match?(%r{\A[A-Za-z0-9_.,:/@+=-]+\z})
81
+ # return str if Shellwords.shellescape(str) == str
82
+
83
+ # Otherwise use single quotes
84
+ "'#{str.gsub("'", %q('\'\''))}'"
85
+ end
86
+
87
+ # Execute a process securely without shell.
88
+ #
89
+ # Execution `mode` can be:
90
+ # - :execute -> Kernel.system, return nil
91
+ # - :background -> Process.spawn, return pid
92
+ # - :capture -> Open3.capture3, return stdout
93
+ #
94
+ # @param cmd [Array<String>] Executable and arguments (mapped "to_s")
95
+ # @param mode [:execute,:background,:capture] Execution mode
96
+ # @param kwargs [Hash] Additional arguments to underlying method
97
+ # @option kwargs [Hash] :env Environment variables
98
+ # @option kwargs [Boolean] :exception for :capture mode, raise error if process fails
99
+ # @option kwargs [Boolean] :close_others for :background mode
100
+ # @return [nil] for :execute mode
101
+ # @return [Integer] pid for :background mode
102
+ # @return [String] stdout for :capture mode
89
103
  def secure_execute(*cmd, mode: :execute, **kwargs)
90
104
  cmd = cmd.map(&:to_s)
91
105
  Aspera.assert(cmd.size.positive?, type: ArgumentError){'executable must be present'}
92
106
  Aspera.assert_values(mode, PROCESS_MODES, type: ArgumentError){'mode'}
93
107
  Log.log.debug do
94
108
  parts = [mode.to_s, 'command:']
95
- kwargs[:env]&.each{ |k, v| parts << "#{k}=#{Shellwords.shellescape(v.to_s)}"}
96
- cmd.each{ |a| parts << Shellwords.shellescape(a)}
109
+ kwargs[:env]&.each{ |k, v| parts << "#{k}=#{shell_escape_pretty(v.to_s)}"}
110
+ cmd.each{ |a| parts << shell_escape_pretty(a)}
97
111
  parts.join(' ')
98
112
  end
99
113
  case mode
@@ -52,9 +52,9 @@ module Aspera
52
52
  operation: 'POST',
53
53
  subpath: "packages/#{package['id']}/transfer_spec/upload",
54
54
  query: {transfer_type: Api::Faspex::TRANSFER_CONNECT},
55
- content_type: Rest::MIME_JSON,
55
+ content_type: Mime::JSON,
56
56
  body: {paths: [{'destination'=>'/'}]},
57
- headers: {'Accept' => Rest::MIME_JSON}
57
+ headers: {'Accept' => Mime::JSON}
58
58
  )
59
59
  transfer_spec.delete('authentication')
60
60
  # but we place it in a Faspex package creation response
@@ -80,20 +80,20 @@ module Aspera
80
80
  faspex4_send_to_faspex5(faspex_pkg_parameters)
81
81
  else Aspera.error_unexpected_value(@app_api.class.name)
82
82
  end
83
- Log.log.info{"faspex_package_create_result=#{faspex_package_create_result}"}
83
+ Log.log.debug{"faspex_package_create_result=#{faspex_package_create_result}"}
84
84
  response.status = 200
85
- response.content_type = Rest::MIME_JSON
85
+ response.content_type = Mime::JSON
86
86
  response.body = JSON.generate(faspex_package_create_result)
87
87
  rescue => e
88
88
  response.status = 500
89
- response['Content-Type'] = Rest::MIME_JSON
89
+ response['Content-Type'] = Mime::JSON
90
90
  response.body = {error: e.message, stacktrace: e.backtrace}.to_json
91
91
  Log.log.error(e.message)
92
92
  Log.log.debug{e.backtrace.join("\n")}
93
93
  end
94
94
  else
95
95
  response.status = 400
96
- response['Content-Type'] = Rest::MIME_JSON
96
+ response['Content-Type'] = Mime::JSON
97
97
  response.body = {error: 'Unsupported endpoint'}.to_json
98
98
  end
99
99
  end
@@ -27,17 +27,18 @@ module Aspera
27
27
  # :reek:UncommunicativeMethodName
28
28
  def do_POST(request, response)
29
29
  Log.log.debug{"request=#{request.path}"}
30
+ Log.log.debug{"query=#{request.query}"}
30
31
  begin
31
- # only accept requests on the root
32
+ # Only accept requests on the root
32
33
  if !request.path.start_with?(@parameters[:root])
33
34
  response.status = 400
34
- response['Content-Type'] = Rest::MIME_JSON
35
+ response['Content-Type'] = Mime::JSON
35
36
  response.body = {status: 'error', message: 'Request outside domain'}.to_json
36
37
  return
37
38
  end
38
39
  if request.body.nil?
39
40
  response.status = 400
40
- response['Content-Type'] = Rest::MIME_JSON
41
+ response['Content-Type'] = Mime::JSON
41
42
  response.body = {status: 'error', message: 'Empty request'}.to_json
42
43
  return
43
44
  end
@@ -48,18 +49,23 @@ module Aspera
48
49
  Log.log.debug{"script=#{script_path}"}
49
50
  webhook_parameters = JSON.parse(request.body)
50
51
  Log.dump(:webhook_parameters, webhook_parameters)
51
- # env expects only strings
52
- environment = webhook_parameters.each_with_object({}){ |(k, v), h| h[k] = v.to_s}
53
- post_proc_pid = Environment.secure_execute(script_path, mode: :background, env: environment)
54
- Timeout.timeout(@parameters[:timeout_seconds]) do
55
- # "wait" for process to avoid zombie
56
- Process.wait(post_proc_pid)
57
- post_proc_pid = nil
52
+ if request.query.key?('lambda')
53
+ # Code can throw exception, source code must return a lambda
54
+ Environment.secure_eval(File.read(script_path), __FILE__, __LINE__).call(webhook_parameters)
55
+ else
56
+ # env expects only strings
57
+ environment = webhook_parameters.each_with_object({}){ |(k, v), h| h[k] = v.to_s}
58
+ post_proc_pid = Environment.secure_execute(script_path, mode: :background, env: environment)
59
+ Timeout.timeout(@parameters[:timeout_seconds]) do
60
+ # "wait" for process to avoid zombie
61
+ Process.wait(post_proc_pid)
62
+ post_proc_pid = nil
63
+ end
64
+ process_status = $CHILD_STATUS
65
+ raise "script #{script_path} failed with code #{process_status.exitstatus}" if !process_status.success? && @parameters[:fail_on_error]
58
66
  end
59
- process_status = $CHILD_STATUS
60
- raise "script #{script_path} failed with code #{process_status.exitstatus}" if !process_status.success? && @parameters[:fail_on_error]
61
67
  response.status = 200
62
- response.content_type = Rest::MIME_JSON
68
+ response.content_type = Mime::JSON
63
69
  response.body = JSON.generate({status: 'success', script: script_path, exit_code: process_status.exitstatus})
64
70
  Log.log.debug{'Script executed successfully'}
65
71
  rescue => e
@@ -70,7 +76,7 @@ module Aspera
70
76
  Log.log.error("Killed process: #{post_proc_pid}")
71
77
  end
72
78
  response.status = 500
73
- response['Content-Type'] = Rest::MIME_JSON
79
+ response['Content-Type'] = Mime::JSON
74
80
  response.body = {status: 'error', script: script_path, message: e.message}.to_json
75
81
  end
76
82
  end
@@ -26,6 +26,10 @@ unless Hash.method_defined?(:symbolize_keys)
26
26
  def symbolize_keys
27
27
  return transform_keys(&:to_sym)
28
28
  end
29
+
30
+ def symbolize_keys!
31
+ return transform_keys!(&:to_sym)
32
+ end
29
33
  end
30
34
  end
31
35
 
@@ -35,5 +39,9 @@ unless Hash.method_defined?(:stringify_keys)
35
39
  def stringify_keys
36
40
  return transform_keys(&:to_s)
37
41
  end
42
+
43
+ def stringify_keys!
44
+ return transform_keys!(&:to_s)
45
+ end
38
46
  end
39
47
  end
data/lib/aspera/log.rb CHANGED
@@ -65,11 +65,8 @@ module Aspera
65
65
 
66
66
  # Class methods
67
67
  class << self
68
- # Applies the provided list of string decoration (colors) to the value.
69
- # @param value [String] Value to enhance.
70
- # @param colors [Array(Symbol)] List of decorations
71
- def apply_colors(value, colors)
72
- colors.inject(value){ |s, c| s.send(c)}
68
+ def short_levl(level)
69
+ "#{level[0, 3]}#{level[-1]}"
73
70
  end
74
71
 
75
72
  # Get the logger object of singleton
@@ -154,8 +151,8 @@ module Aspera
154
151
 
155
152
  def formatter=(formatter)
156
153
  if formatter.is_a?(String)
157
- raise Error, "Unknown formatter #{formatter}, use one of: #{FORMATTERS.keys.join(', ')}" unless FORMATTERS.key?(formatter.to_sym)
158
- formatter = FORMATTERS[formatter.to_sym]
154
+ raise Error, "Unknown formatter #{formatter}, use one of: #{FORMATTERS.join(', ')}" unless FORMATTER_LAMBDAS.key?(formatter.to_sym)
155
+ formatter = FORMATTER_LAMBDAS[formatter.to_sym]
159
156
  elsif !formatter.respond_to?(:call) && !formatter.is_a?(Logger::Formatter)
160
157
  raise Error, 'Formatter must be a String, a Logger::Formatter or a Proc'
161
158
  end
@@ -174,11 +171,10 @@ module Aspera
174
171
  Logger::SEVERITY_LABEL[@logger.level].downcase
175
172
  end
176
173
 
177
- # Change underlying logger, but keep log level
174
+ # Change underlying logger, but keep log level (default: INFO)
178
175
  def logger_type=(new_log_type)
179
- current_severity_integer = @logger.level unless @logger.nil?
180
- current_severity_integer = ENV.fetch('AS_LOG_LEVEL', nil) if current_severity_integer.nil? && ENV.key?('AS_LOG_LEVEL')
181
- current_severity_integer = Logger::Severity::WARN if current_severity_integer.nil?
176
+ # [Integer]
177
+ current_severity_integer = @logger&.level || ENV['AS_LOG_LEVEL']&.to_i || Logger::Severity::INFO
182
178
  case new_log_type
183
179
  when :stderr
184
180
  @logger = Logger.new($stderr, progname: @program_name, formatter: DEFAULT_FORMATTER)
@@ -227,18 +223,22 @@ module Aspera
227
223
  UNKNOWN: %i{blink}
228
224
  }.freeze
229
225
 
230
- # Short levels with color
231
- LVL_COLOR = LVL_DECO.map{ |k, v| [k, apply_colors("#{k[..2]}#{k[-1]}", v)]}.to_h.freeze
226
+ # Short (4-letters) levels with color
227
+ LVL_COLOR = LVL_DECO.to_h do |k, v|
228
+ [k, short_levl(k).apply(*v)]
229
+ end.freeze
232
230
 
233
231
  DEFAULT_FORMATTER = ->(s, _d, _p, m){"#{LVL_COLOR[s]} #{m}\n"}
234
232
 
235
233
  # pre-defined formatters
236
- FORMATTERS = {
234
+ FORMATTER_LAMBDAS = {
237
235
  standard: Logger::Formatter.new,
238
236
  default: DEFAULT_FORMATTER,
239
237
  caller: ->(s, _d, _p, m){"#{LVL_COLOR[s]} #{Log.caller_method}\n#{m}\n"}
240
238
  }.freeze
241
239
 
242
- private_constant :LVL_DECO, :LVL_COLOR, :DEFAULT_FORMATTER, :FORMATTERS
240
+ FORMATTERS = FORMATTER_LAMBDAS.keys
241
+
242
+ private_constant :LVL_DECO, :DEFAULT_FORMATTER, :FORMATTER_LAMBDAS
243
243
  end
244
244
  end
@@ -26,6 +26,28 @@ module Aspera
26
26
  def list(items)
27
27
  items.map{ |i| "- #{i}"}.join("\n")
28
28
  end
29
+
30
+ def heading(title, level: 1)
31
+ "#{'#' * level} #{title}\n\n"
32
+ end
33
+
34
+ # type: NOTE CAUTION WARNING IMPORTANT TIP INFO
35
+ def admonition(lines, type: 'INFO')
36
+ "> [!{type}]\n#{lines.map{ |l| "> #{l}"}.join("\n")}\n\n"
37
+ end
38
+
39
+ def code(lines, type: 'shell')
40
+ "```#{type}\n#{lines.join("\n")}\n```\n\n"
41
+ end
42
+
43
+ # inline code
44
+ def icode(text)
45
+ "`#{text}`"
46
+ end
47
+
48
+ def paragraph(text)
49
+ "#{text}\n\n"
50
+ end
29
51
  end
30
52
  end
31
53
  end
@@ -328,7 +328,7 @@ module Aspera
328
328
 
329
329
  def set_json_response(request, response, json, code: 200)
330
330
  response.status = code
331
- response['Content-Type'] = Rest::MIME_JSON
331
+ response['Content-Type'] = Mime::JSON
332
332
  response.body = json.to_json
333
333
  Log.log.trace1{Log.obj_dump("response for #{request.request_method} #{request.path}", json)}
334
334
  end
@@ -53,7 +53,7 @@ module Aspera
53
53
  def create_token_call(creation_params)
54
54
  Log.log.debug{'Generating a new token'.bg_green}
55
55
  return @api.create(@path_token, nil, query: creation_params, ret: :resp) if @use_query
56
- return @api.create(@path_token, creation_params, content_type: Rest::MIME_WWW, ret: :resp)
56
+ return @api.create(@path_token, creation_params, content_type: Mime::WWW, ret: :resp)
57
57
  end
58
58
 
59
59
  # Create base parameters for token creation calls
@@ -99,7 +99,7 @@ module Aspera
99
99
  # lets try the existing refresh token
100
100
  # NOTE: AoC admin token has no refresh, and lives by default 1800secs
101
101
  if !refresh_token.nil?
102
- Log.log.info{"refresh token=[#{refresh_token}]".bg_green}
102
+ Log.log.debug{"refresh token=[#{refresh_token}]"}
103
103
  begin
104
104
  http = create_token_call(base_params(add_secret: true).merge(grant_type: 'refresh_token', refresh_token: refresh_token))
105
105
  # Save only if success
@@ -24,9 +24,9 @@ module Aspera
24
24
  operation: 'POST',
25
25
  subpath: path_token,
26
26
  query: @query.merge(scope: params[:scope]), # scope is here because it may change over time (node)
27
- content_type: Rest::MIME_JSON,
27
+ content_type: Mime::JSON,
28
28
  body: @body,
29
- headers: {'Accept' => Rest::MIME_JSON},
29
+ headers: {'Accept' => Mime::JSON},
30
30
  ret: :resp
31
31
  )
32
32
  end
@@ -35,7 +35,7 @@ module Aspera
35
35
  base_params.merge(response_type: 'code', redirect_uri: @redirect_uri, state: random_state)
36
36
  )
37
37
  # here, we need a human to authorize on a web page
38
- Log.log.info{"login_page_url=#{login_page_url}".bg_red.gray}
38
+ Log.log.debug{"login_page_url=#{login_page_url}"}
39
39
  # start a web server to receive request code
40
40
  web_server = WebAuth.new(@redirect_uri, self.class.additional_info)
41
41
  # start browser on login page
@@ -23,18 +23,18 @@ module Aspera
23
23
  # one of CONVERSION_TYPES
24
24
  attr_reader :conversion_type
25
25
 
26
- # node API mime types are from: http://svn.apache.org/repos/asf/httpd/httpd/trunk/docs/conf/mime.types
27
- # the resulting preview file type is taken from destination file extension.
28
- # conversion methods are provided by private methods: convert_<conversion_type>_to_<preview_format>
26
+ # Node API MIME types are from: http://svn.apache.org/repos/asf/httpd/httpd/trunk/docs/conf/mime.types
27
+ # The resulting preview file type is taken from destination file extension.
28
+ # Conversion methods are provided by private methods: convert_<conversion_type>_to_<preview_format>
29
29
  # -> conversion_type is one of FileTypes::CONVERSION_TYPES
30
30
  # -> preview_format is one of Generator::PREVIEW_FORMATS
31
- # the conversion video->mp4 is implemented in methods: convert_video_to_mp4_using_<video_conversion>
31
+ # The conversion video->mp4 is implemented in methods: convert_video_to_mp4_using_<video_conversion>
32
32
  # -> conversion method is one of Generator::VIDEO_CONVERSION_METHODS
33
33
  # @param src [String] source file path
34
34
  # @param dst [String] destination file path
35
35
  # @param options [Options] All conversion options
36
36
  # @param main_temp_dir [String] Main temp folder, sub folder will be created for generation
37
- # @param api_mime_type [String,nil] Optional mime type as provided by node api (or nil)
37
+ # @param api_mime_type [String,nil] Optional MIME type as provided by node api (or nil)
38
38
  def initialize(src, dst, options, main_temp_dir, api_mime_type)
39
39
  @source_file_path = src
40
40
  @destination_file_path = dst
@@ -57,9 +57,9 @@ module Aspera
57
57
  Aspera.assert(respond_to?(@processing_method, true)){"no processing known for #{conversion_type} -> #{@preview_format_sym}"}
58
58
  end
59
59
 
60
- # create preview as specified in constructor
60
+ # Create preview as specified in constructor.
61
61
  def generate
62
- Log.log.info{"#{@source_file_path}->#{@destination_file_path} (#{@processing_method})"}
62
+ Log.log.debug{"#{@source_file_path}->#{@destination_file_path} (#{@processing_method})"}
63
63
  begin
64
64
  send(@processing_method)
65
65
  # check that generated size does not exceed maximum
@@ -76,17 +76,17 @@ module Aspera
76
76
 
77
77
  private
78
78
 
79
- # creates a unique temp folder for file
79
+ # Creates a unique temp folder for file.
80
80
  def this_tmpdir
81
81
  FileUtils.mkdir_p(@temp_folder)
82
82
  return @temp_folder
83
83
  end
84
84
 
85
- # @return offset in seconds suitable for ffmpeg -ss option
86
85
  # @param duration of video
87
86
  # @param start_offset of parts
88
87
  # @param total_count of parts
89
88
  # @param index of part (start at 1)
89
+ # @return [Integer] offset in seconds suitable for ffmpeg -ss option
90
90
  def get_offset(duration, start_offset, total_count, index)
91
91
  Aspera.assert_type(duration, Float){'duration'}
92
92
  return start_offset + ((index - 1) * (duration - start_offset) / total_count)