aspera-cli 4.13.0 → 4.15.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (99) hide show
  1. checksums.yaml +4 -4
  2. checksums.yaml.gz.sig +0 -0
  3. data/CHANGELOG.md +81 -7
  4. data/CONTRIBUTING.md +22 -6
  5. data/README.md +2038 -1080
  6. data/bin/ascli +18 -9
  7. data/bin/asession +12 -14
  8. data/examples/dascli +1 -1
  9. data/examples/proxy.pac +1 -1
  10. data/examples/rubyc +24 -0
  11. data/lib/aspera/aoc.rb +219 -159
  12. data/lib/aspera/ascmd.rb +25 -14
  13. data/lib/aspera/cli/basic_auth_plugin.rb +12 -9
  14. data/lib/aspera/cli/error.rb +17 -0
  15. data/lib/aspera/cli/extended_value.rb +47 -12
  16. data/lib/aspera/cli/formatter.rb +260 -179
  17. data/lib/aspera/cli/hints.rb +80 -0
  18. data/lib/aspera/cli/main.rb +104 -156
  19. data/lib/aspera/cli/manager.rb +259 -209
  20. data/lib/aspera/cli/plugin.rb +123 -63
  21. data/lib/aspera/cli/plugins/alee.rb +2 -3
  22. data/lib/aspera/cli/plugins/aoc.rb +341 -261
  23. data/lib/aspera/cli/plugins/ats.rb +22 -21
  24. data/lib/aspera/cli/plugins/bss.rb +5 -5
  25. data/lib/aspera/cli/plugins/config.rb +578 -627
  26. data/lib/aspera/cli/plugins/console.rb +44 -6
  27. data/lib/aspera/cli/plugins/cos.rb +15 -17
  28. data/lib/aspera/cli/plugins/faspex.rb +114 -100
  29. data/lib/aspera/cli/plugins/faspex5.rb +411 -264
  30. data/lib/aspera/cli/plugins/node.rb +354 -259
  31. data/lib/aspera/cli/plugins/orchestrator.rb +61 -29
  32. data/lib/aspera/cli/plugins/preview.rb +82 -90
  33. data/lib/aspera/cli/plugins/server.rb +79 -32
  34. data/lib/aspera/cli/plugins/shares.rb +55 -42
  35. data/lib/aspera/cli/sync_actions.rb +68 -0
  36. data/lib/aspera/cli/transfer_agent.rb +66 -73
  37. data/lib/aspera/cli/transfer_progress.rb +74 -0
  38. data/lib/aspera/cli/version.rb +1 -1
  39. data/lib/aspera/colors.rb +12 -8
  40. data/lib/aspera/command_line_builder.rb +14 -11
  41. data/lib/aspera/cos_node.rb +3 -2
  42. data/lib/aspera/data/6 +0 -0
  43. data/lib/aspera/environment.rb +24 -9
  44. data/lib/aspera/fasp/agent_aspera.rb +126 -0
  45. data/lib/aspera/fasp/agent_base.rb +31 -77
  46. data/lib/aspera/fasp/agent_connect.rb +25 -21
  47. data/lib/aspera/fasp/agent_direct.rb +89 -103
  48. data/lib/aspera/fasp/agent_httpgw.rb +231 -149
  49. data/lib/aspera/fasp/agent_node.rb +41 -34
  50. data/lib/aspera/fasp/agent_trsdk.rb +75 -32
  51. data/lib/aspera/fasp/error_info.rb +4 -2
  52. data/lib/aspera/fasp/faux_file.rb +52 -0
  53. data/lib/aspera/fasp/installation.rb +53 -195
  54. data/lib/aspera/fasp/management.rb +244 -0
  55. data/lib/aspera/fasp/parameters.rb +71 -37
  56. data/lib/aspera/fasp/parameters.yaml +76 -8
  57. data/lib/aspera/fasp/products.rb +162 -0
  58. data/lib/aspera/fasp/resume_policy.rb +3 -3
  59. data/lib/aspera/fasp/transfer_spec.rb +7 -6
  60. data/lib/aspera/fasp/uri.rb +26 -24
  61. data/lib/aspera/faspex_gw.rb +2 -2
  62. data/lib/aspera/faspex_postproc.rb +2 -2
  63. data/lib/aspera/hash_ext.rb +14 -4
  64. data/lib/aspera/json_rpc.rb +49 -0
  65. data/lib/aspera/keychain/macos_security.rb +13 -13
  66. data/lib/aspera/line_logger.rb +23 -0
  67. data/lib/aspera/log.rb +58 -16
  68. data/lib/aspera/node.rb +157 -92
  69. data/lib/aspera/oauth.rb +37 -19
  70. data/lib/aspera/open_application.rb +4 -4
  71. data/lib/aspera/persistency_action_once.rb +1 -1
  72. data/lib/aspera/persistency_folder.rb +2 -2
  73. data/lib/aspera/preview/file_types.rb +4 -2
  74. data/lib/aspera/preview/generator.rb +22 -35
  75. data/lib/aspera/preview/options.rb +2 -0
  76. data/lib/aspera/preview/terminal.rb +73 -16
  77. data/lib/aspera/preview/utils.rb +21 -28
  78. data/lib/aspera/proxy_auto_config.js +2 -2
  79. data/lib/aspera/rest.rb +136 -68
  80. data/lib/aspera/rest_call_error.rb +1 -1
  81. data/lib/aspera/rest_error_analyzer.rb +15 -14
  82. data/lib/aspera/rest_errors_aspera.rb +37 -34
  83. data/lib/aspera/secret_hider.rb +18 -15
  84. data/lib/aspera/ssh.rb +5 -2
  85. data/lib/aspera/sync.rb +127 -119
  86. data/lib/aspera/temp_file_manager.rb +10 -3
  87. data/lib/aspera/web_auth.rb +10 -7
  88. data/lib/aspera/web_server_simple.rb +9 -4
  89. data.tar.gz.sig +0 -0
  90. metadata +34 -17
  91. metadata.gz.sig +0 -0
  92. data/docs/test_env.conf +0 -186
  93. data/lib/aspera/cli/listener/line_dump.rb +0 -19
  94. data/lib/aspera/cli/listener/logger.rb +0 -22
  95. data/lib/aspera/cli/listener/progress.rb +0 -50
  96. data/lib/aspera/cli/listener/progress_multi.rb +0 -84
  97. data/lib/aspera/cli/plugins/sync.rb +0 -44
  98. data/lib/aspera/data/7 +0 -0
  99. data/lib/aspera/fasp/listener.rb +0 -13
@@ -1,23 +1,55 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- require 'aspera/cli/plugins/node'
3
+ require 'aspera/cli/basic_auth_plugin'
4
+ require 'aspera/nagios'
4
5
  require 'xmlsimple'
5
6
 
6
7
  module Aspera
7
8
  module Cli
8
9
  module Plugins
9
10
  class Orchestrator < Aspera::Cli::BasicAuthPlugin
11
+ class << self
12
+ STANDARD_PATH = '/aspera/orchestrator'
13
+ def detect(address_or_url)
14
+ address_or_url = "https://#{address_or_url}" unless address_or_url.match?(%r{^[a-z]{1,6}://})
15
+ urls = [address_or_url]
16
+ urls.push("#{address_or_url}#{STANDARD_PATH}") unless address_or_url.end_with?(STANDARD_PATH)
17
+ urls.each do |base_url|
18
+ next unless base_url.match?('https?://')
19
+ api = Rest.new(base_url: base_url)
20
+ test_endpoint = 'api/remote_node_ping'
21
+ result = api.read(test_endpoint, {format: :json})
22
+ next unless result[:data]['remote_orchestrator_info']
23
+ url = result[:http].uri.to_s
24
+ return {
25
+ version: result[:data]['remote_orchestrator_info']['orchestrator-version'],
26
+ url: url[0..url.index(test_endpoint) - 2]
27
+ }
28
+ rescue StandardError => e
29
+ Log.log.debug{"detect error: #{e}"}
30
+ end
31
+ return nil
32
+ end
33
+
34
+ def wizard(object:, private_key_path: nil, pub_key_pem: nil)
35
+ options = object.options
36
+ return {
37
+ preset_value: {
38
+ url: options.get_option(:url, mandatory: true),
39
+ username: options.get_option(:username, mandatory: true),
40
+ password: options.get_option(:password, mandatory: true)
41
+ },
42
+ test_args: 'workflow list'
43
+ }
44
+ end
45
+ end
46
+
10
47
  def initialize(env)
11
48
  super(env)
12
- options.add_opt_simple(:params, 'parameters hash table, use @json:{"param":"value"}')
13
- options.add_opt_simple(:result, "specify result value as: 'work step:parameter'")
14
- options.add_opt_boolean(:synchronous, 'work step:parameter expected as result')
15
- options.add_opt_list(:ret_style, %i[header arg ext], 'how return type is requested in api')
16
- options.add_opt_list(:auth_style, %i[arg_pass head_basic apikey], 'authentication type')
17
- options.set_option(:params, {})
18
- options.set_option(:synchronous, :no)
19
- options.set_option(:ret_style, :arg)
20
- options.set_option(:auth_style, :head_basic)
49
+ options.declare(:result, "Specify result value as: 'work_step:parameter'")
50
+ options.declare(:synchronous, 'Wait for completion', values: :bool, default: :no)
51
+ options.declare(:ret_style, 'How return type is requested in api', values: %i[header arg ext], default: :arg)
52
+ options.declare(:auth_style, 'Authentication type', values: %i[arg_pass head_basic apikey], default: :head_basic)
21
53
  options.parse_options!
22
54
  end
23
55
 
@@ -49,7 +81,7 @@ module Aspera
49
81
  call_args[:subpath] = "#{opt[:prefix]}/#{call_args[:subpath]}" unless opt[:prefix].nil?
50
82
  # specify id if necessary
51
83
  call_args[:subpath] = "#{call_args[:subpath]}/#{opt[:id]}" if opt.key?(:id)
52
- call_type = options.get_option(:ret_style, is_type: :mandatory)
84
+ call_type = options.get_option(:ret_style, mandatory: true)
53
85
  call_type = opt[:ret_style] if opt.key?(:ret_style)
54
86
  format = 'json'
55
87
  format = opt[:format] if opt.key?(:format)
@@ -68,24 +100,24 @@ module Aspera
68
100
  end
69
101
  result = @api_orch.call(call_args)
70
102
  result[:data] = XmlSimple.xml_in(result[:http].body, opt[:xml_opt] || {'ForceArray' => true}) if format.eql?('xml')
71
- Log.dump(:data, result[:data])
103
+ Log.log.debug{Log.dump(:data, result[:data])}
72
104
  return result
73
105
  end
74
106
 
75
107
  def execute_action
76
- rest_params = {base_url: options.get_option(:url, is_type: :mandatory)}
77
- case options.get_option(:auth_style, is_type: :mandatory)
108
+ rest_params = {base_url: options.get_option(:url, mandatory: true)}
109
+ case options.get_option(:auth_style, mandatory: true)
78
110
  when :arg_pass
79
111
  rest_params[:auth] = {
80
112
  type: :url,
81
- url_creds: {
82
- 'login' => options.get_option(:username, is_type: :mandatory),
83
- 'password' => options.get_option(:password, is_type: :mandatory) }}
113
+ url_query: {
114
+ 'login' => options.get_option(:username, mandatory: true),
115
+ 'password' => options.get_option(:password, mandatory: true) }}
84
116
  when :head_basic
85
117
  rest_params[:auth] = {
86
118
  type: :basic,
87
- username: options.get_option(:username, is_type: :mandatory),
88
- password: options.get_option(:password, is_type: :mandatory) }
119
+ username: options.get_option(:username, mandatory: true),
120
+ password: options.get_option(:password, mandatory: true) }
89
121
  when :apikey
90
122
  raise 'Not implemented'
91
123
  end
@@ -122,9 +154,9 @@ module Aspera
122
154
  end
123
155
  case command
124
156
  when :status
125
- options = {}
126
- options[:id] = wf_id unless wf_id.eql?(VAL_ALL)
127
- result = call_ao('workflows_status', options)[:data]
157
+ call_opts = {}
158
+ call_opts[:id] = wf_id unless wf_id.eql?(ExtendedValue::ALL)
159
+ result = call_ao('workflows_status', call_opts)[:data]
128
160
  return {type: :object_list, data: result['workflows']['workflow']}
129
161
  when :list
130
162
  result = call_ao('workflows_list', id: 0)[:data]
@@ -149,18 +181,18 @@ module Aspera
149
181
  }
150
182
  call_params = {format: :json}
151
183
  override_accept = nil
152
- # set external parameters if any
153
- self.options.get_option(:params, is_type: :mandatory).each do |name, value|
184
+ # get external parameters if any
185
+ options.get_next_argument('external_parameters', mandatory: false, type: Hash, default: {}).each do |name, value|
154
186
  call_params["external_parameters[#{name}]"] = value
155
187
  end
156
188
  # synchronous call ?
157
- call_params['synchronous'] = true if self.options.get_option(:synchronous, is_type: :mandatory)
189
+ call_params['synchronous'] = true if options.get_option(:synchronous, mandatory: true)
158
190
  # expected result for synchro call ?
159
- expected = self.options.get_option(:result)
160
- unless expected.nil?
191
+ result_location = options.get_option(:result)
192
+ unless result_location.nil?
161
193
  result[:type] = :status
162
- fields = expected.split(':')
163
- raise "Expects: work_step:result_name format, but got #{expected}" if fields.length != 2
194
+ fields = result_location.split(':')
195
+ raise Cli::BadArgument, "Expects: work_step:result_name : #{result_location}" if fields.length != 2
164
196
  call_params['explicit_output_step'] = fields[0]
165
197
  call_params['explicit_output_variable'] = fields[1]
166
198
  # implicitly, call is synchronous
@@ -1,17 +1,18 @@
1
1
  # frozen_string_literal: true
2
2
 
3
+ # cspell:ignore trevents
3
4
  require 'aspera/cli/basic_auth_plugin'
4
5
  require 'aspera/preview/generator'
5
6
  require 'aspera/preview/options'
6
7
  require 'aspera/preview/utils'
7
8
  require 'aspera/preview/file_types'
9
+ require 'aspera/preview/terminal'
8
10
  require 'aspera/fasp/transfer_spec'
9
11
  require 'aspera/persistency_action_once'
10
12
  require 'aspera/node'
11
13
  require 'aspera/hash_ext'
12
14
  require 'aspera/timer_limiter'
13
15
  require 'aspera/id_generator'
14
- require 'date'
15
16
  require 'securerandom'
16
17
 
17
18
  module Aspera
@@ -26,8 +27,11 @@ module Aspera
26
27
  PREVIEW_BASENAME = 'preview'
27
28
  # subfolder in system tmp folder
28
29
  TMP_DIR_PREFIX = 'prev_tmp'
30
+ # same value as in aspera.conf
29
31
  DEFAULT_PREVIEWS_FOLDER = 'previews'
32
+ # mark that this is used by a particular access key
30
33
  AK_MARKER_FILE = '.aspera_access_key'
34
+ # URL prefix for local storage
31
35
  PVCL_LOCAL_STORAGE = 'file:///'
32
36
  LOG_LIMITER_SEC = 30.0
33
37
  private_constant :PREV_GEN_TAG,
@@ -53,44 +57,45 @@ module Aspera
53
57
  @gen_options = Aspera::Preview::Options.new
54
58
  # used to trigger periodic processing
55
59
  @periodic = TimerLimiter.new(LOG_LIMITER_SEC)
60
+ # Proc
61
+ @filter_block = nil
56
62
  # link CLI options to gen_info attributes
57
- options.set_obj_attr(:skip_format, self, :option_skip_format, []) # no skip
58
- options.set_obj_attr(:folder_reset_cache, self, :option_folder_reset_cache, :no)
59
- options.set_obj_attr(:skip_types, self, :option_skip_types)
60
- options.set_obj_attr(:previews_folder, self, :option_previews_folder, DEFAULT_PREVIEWS_FOLDER)
61
- options.set_obj_attr(:skip_folders, self, :option_skip_folders, []) # no skip
62
- options.set_obj_attr(:overwrite, self, :option_overwrite, :mtime)
63
- options.set_obj_attr(:file_access, self, :option_file_access, :local)
64
- options.add_opt_list(:skip_format, Aspera::Preview::Generator::PREVIEW_FORMATS, 'skip this preview format (multiple possible)')
65
- options.add_opt_list(:folder_reset_cache, %i[no header read], 'force detection of generated preview by refresh cache')
66
- options.add_opt_simple(:skip_types, 'skip types in comma separated list')
67
- options.add_opt_simple(:previews_folder, 'preview folder in storage root')
68
- options.add_opt_simple(:temp_folder, 'path to temp folder')
69
- options.add_opt_simple(:skip_folders, 'list of folder to skip')
70
- options.add_opt_simple(:case, 'basename of output for for test')
71
- options.add_opt_simple(:scan_path, 'subpath in folder id to start scan in (default=/)')
72
- options.add_opt_simple(:scan_id, 'folder id in storage to start scan in, default is access key main folder id')
73
- options.add_opt_boolean(:mimemagic, 'use Mime type detection of gem mimemagic')
74
- options.add_opt_list(:overwrite, %i[always never mtime], 'when to overwrite result file')
75
- options.add_opt_list(:file_access, %i[local remote], 'how to read and write files in repository')
76
- options.set_option(:temp_folder, Dir.tmpdir)
77
- options.set_option(:mimemagic, false)
63
+ options.declare(
64
+ :skip_format, 'Skip this preview format (multiple possible)', values: Aspera::Preview::Generator::PREVIEW_FORMATS,
65
+ handler: {o: self, m: :option_skip_format}, default: [])
66
+ options.declare(
67
+ :folder_reset_cache, 'Force detection of generated preview by refresh cache',
68
+ values: %i[no header read],
69
+ handler: {o: self, m: :option_folder_reset_cache},
70
+ default: :no)
71
+ options.declare(:skip_types, 'Skip types in comma separated list', handler: {o: self, m: :option_skip_types})
72
+ options.declare(:previews_folder, 'Preview folder in storage root', handler: {o: self, m: :option_previews_folder}, default: DEFAULT_PREVIEWS_FOLDER)
73
+ options.declare(:temp_folder, 'Path to temp folder', default: Dir.tmpdir)
74
+ options.declare(:skip_folders, 'List of folder to skip', handler: {o: self, m: :option_skip_folders}, default: [])
75
+ options.declare(:base, 'Basename of output for for test')
76
+ options.declare(:scan_path, 'Subpath in folder id to start scan in (default=/)')
77
+ options.declare(:scan_id, 'Folder id in storage to start scan in, default is access key main folder id')
78
+ options.declare(:mimemagic, 'Use Mime type detection of gem mimemagic', values: :bool, default: false)
79
+ options.declare(:overwrite, 'When to overwrite result file', values: %i[always never mtime], handler: {o: self, m: :option_overwrite}, default: :mtime)
80
+ options.declare(
81
+ :file_access, 'How to read and write files in repository',
82
+ values: %i[local remote],
83
+ handler: {o: self, m: :option_file_access},
84
+ default: :local)
78
85
 
79
86
  # add other options for generator (and set default values)
80
87
  Aspera::Preview::Options::DESCRIPTIONS.each do |opt|
81
- options.set_obj_attr(opt[:name], @gen_options, opt[:name], opt[:default])
82
- if opt.key?(:values)
83
- options.add_opt_list(opt[:name], opt[:values], opt[:description])
88
+ values = if opt.key?(:values)
89
+ opt[:values]
84
90
  elsif Cli::Manager::BOOLEAN_SIMPLE.include?(opt[:default])
85
- options.add_opt_boolean(opt[:name], opt[:description])
86
- else
87
- options.add_opt_simple(opt[:name], opt[:description])
91
+ :bool
88
92
  end
93
+ options.declare(opt[:name], opt[:description].capitalize, values: values, handler: {o: @gen_options, m: opt[:name]}, default: opt[:default])
89
94
  end
90
95
 
91
96
  options.parse_options!
92
97
  raise 'skip_folder shall be an Array, use @json:[...]' unless @option_skip_folders.is_a?(Array)
93
- @tmp_folder = File.join(options.get_option(:temp_folder, is_type: :mandatory), "#{TMP_DIR_PREFIX}.#{SecureRandom.uuid}")
98
+ @tmp_folder = File.join(options.get_option(:temp_folder, mandatory: true), "#{TMP_DIR_PREFIX}.#{SecureRandom.uuid}")
94
99
  FileUtils.mkdir_p(@tmp_folder)
95
100
  Log.log.debug{"tmpdir: #{@tmp_folder}"}
96
101
  end
@@ -206,34 +211,12 @@ module Aspera
206
211
  end
207
212
 
208
213
  def do_transfer(direction, folder_id, source_filename, destination='/')
209
- raise 'error' if destination.nil? && direction.eql?(Fasp::TransferSpec::DIRECTION_RECEIVE)
210
- if @default_transfer_spec.nil?
211
- # make a dummy call to get some default transfer parameters
212
- res = @api_node.create('files/upload_setup', {'transfer_requests' => [{'transfer_request' => {'paths' => [{}], 'destination_root' => '/'}}]})
213
- template_ts = res[:data]['transfer_specs'].first['transfer_spec']
214
- # get ports, anyway that should be 33001 for both. add remote_user ?
215
- @default_transfer_spec = %w[ssh_port fasp_port].each_with_object({}){|e, h|h[e] = template_ts[e]; }
216
- if !@default_transfer_spec['remote_user'].eql?(Aspera::Fasp::TransferSpec::ACCESS_KEY_TRANSFER_USER)
217
- Log.log.warn('remote_user shall be xfer')
218
- @default_transfer_spec['remote_user'] = Aspera::Fasp::TransferSpec::ACCESS_KEY_TRANSFER_USER
219
- end
220
- @api_node.ts_basic_token(@default_transfer_spec)
221
- # NOTE: we use the same address for ascp than for node api instead of the one from upload_setup
222
- # TODO: configurable ? useful ?
223
- @default_transfer_spec['remote_host'] = @transfer_server_address
224
- end
225
- t_spec = @default_transfer_spec.merge({
226
- 'direction' => direction,
227
- 'paths' => [{'source' => source_filename}],
228
- 'tags' => {
229
- Fasp::TransferSpec::TAG_RESERVED => {
230
- PREV_GEN_TAG => true,
231
- 'node' => {
232
- 'access_key' => @access_key_self['id'],
233
- 'file_id' => folder_id }}}
214
+ raise 'Internal ERROR' if destination.nil? && direction.eql?(Fasp::TransferSpec::DIRECTION_RECEIVE)
215
+ t_spec = @api_node.transfer_spec_gen4(folder_id, direction, {
216
+ 'paths' => [{'source' => source_filename}],
217
+ 'tags' => {Fasp::TransferSpec::TAG_RESERVED => {PREV_GEN_TAG => true}}
234
218
  })
235
- # force destination
236
- # t_spec['destination_root']=destination
219
+ # force destination, need to set this in transfer agent else it gets overwritten, not do: t_spec['destination_root']=destination
237
220
  transfer.option_transfer_spec_deep_merge({'destination_root' => destination})
238
221
  Main.result_transfer(transfer.start(t_spec))
239
222
  end
@@ -255,6 +238,7 @@ module Aspera
255
238
  def get_infos_remote(gen_infos, entry)
256
239
  # store source directly here
257
240
  local_original_filepath = File.join(@tmp_folder, entry['name'])
241
+ # require 'date'
258
242
  # original_mtime=DateTime.parse(entry['modified_time'])
259
243
  # out: where previews are generated
260
244
  local_entry_preview_dir = File.join(@tmp_folder, entry_preview_folder_name(entry))
@@ -278,9 +262,10 @@ module Aspera
278
262
  "#{entry['id']}#{PREVIEW_FOLDER_SUFFIX}"
279
263
  end
280
264
 
281
- def preview_filename(preview_format, filename=nil)
282
- filename ||= PREVIEW_BASENAME
283
- return "#{filename}.#{preview_format}"
265
+ # Generate a file name based on basename and format (extension)
266
+ def preview_filename(preview_format, base_name=nil)
267
+ base_name ||= PREVIEW_BASENAME
268
+ return "#{base_name}.#{preview_format}"
284
269
  end
285
270
 
286
271
  # generate preview files for one folder entry (file) if necessary
@@ -313,10 +298,13 @@ module Aspera
313
298
  next false if gen_info[:preview_newer_than_original]
314
299
  end
315
300
  end
316
- # need generator for further checks
317
- gen_info[:generator] = Aspera::Preview::Generator.new(@gen_options, gen_info[:src], gen_info[:dst], @tmp_folder, entry['content_type'])
318
- # get conversion_type (if known) and check if supported
319
- next false unless gen_info[:generator].supported?
301
+ begin
302
+ # need generator for further checks
303
+ gen_info[:generator] = Aspera::Preview::Generator.new(gen_info[:src], gen_info[:dst], @gen_options, @tmp_folder, entry['content_type'])
304
+ rescue
305
+ # no conversion supported
306
+ next false
307
+ end
320
308
  # shall we skip it ?
321
309
  next false if @skip_types.include?(gen_info[:generator].conversion_type)
322
310
  # ok we need to generate
@@ -330,7 +318,7 @@ module Aspera
330
318
  # download original file to temp folder
331
319
  do_transfer(Fasp::TransferSpec::DIRECTION_RECEIVE, entry['parent_file_id'], entry['name'], @tmp_folder)
332
320
  end
333
- Log.log.info{"source: #{entry['id']}: #{entry['path']})"}
321
+ Log.log.info{"source: #{entry['id']}: #{entry['path']}"}
334
322
  gen_infos.each do |gen_info|
335
323
  gen_info[:generator].generate rescue nil
336
324
  end
@@ -351,24 +339,22 @@ module Aspera
351
339
  end # generate_preview
352
340
 
353
341
  # scan all files in provided folder entry
354
- # @param scan_start subpath to start folder scan inside
355
- def scan_folder_files(top_entry, scan_start=nil)
356
- if !scan_start.nil?
342
+ # @param top_path subpath to start folder scan inside
343
+ def scan_folder_files(top_entry, top_path=nil)
344
+ unless top_path.nil?
357
345
  # canonical path: start with / and ends with /
358
- scan_start = '/' + scan_start.split('/').reject(&:empty?).join('/')
359
- scan_start = "#{scan_start}/" # unless scan_start.end_with?('/')
346
+ top_path = '/' + top_path.split('/').reject(&:empty?).join('/') + '/'
360
347
  end
361
- filter_block = Aspera::Node.file_matcher(options.get_option(:value))
362
- Log.log.debug{"scan: #{top_entry} : #{scan_start}".green}
348
+ Log.log.debug{"scan: #{top_entry} : #{top_path}".green}
363
349
  # don't use recursive call, use list instead
364
350
  entries_to_process = [top_entry]
365
351
  until entries_to_process.empty?
366
352
  entry = entries_to_process.shift
367
- # process this entry only if it is within the scan_start
353
+ # process this entry only if it is within the top_path
368
354
  entry_path_with_slash = entry['path']
369
355
  Log.log.info{"processing entry #{entry_path_with_slash}"} if @periodic.trigger?
370
356
  entry_path_with_slash = "#{entry_path_with_slash}/" unless entry_path_with_slash.end_with?('/')
371
- if !scan_start.nil? && !scan_start.start_with?(entry_path_with_slash) && !entry_path_with_slash.start_with?(scan_start)
357
+ if !top_path.nil? && !top_path.start_with?(entry_path_with_slash) && !entry_path_with_slash.start_with?(top_path)
372
358
  Log.log.debug{"#{entry['path']} folder (skip start)".bg_red}
373
359
  next
374
360
  end
@@ -376,7 +362,7 @@ module Aspera
376
362
  begin
377
363
  case entry['type']
378
364
  when 'file'
379
- if filter_block.call(entry)
365
+ if @filter_block.call(entry)
380
366
  generate_preview(entry)
381
367
  else
382
368
  Log.log.debug('skip by filter')
@@ -409,11 +395,11 @@ module Aspera
409
395
  end
410
396
  end
411
397
 
412
- ACTIONS = %i[scan events trevents check test].freeze
398
+ ACTIONS = %i[scan events trevents check test show].freeze
413
399
 
414
400
  def execute_action
415
401
  command = options.get_next_command(ACTIONS)
416
- unless %i[check test].include?(command)
402
+ unless %i[check test show].include?(command)
417
403
  # this will use node api
418
404
  @api_node = Aspera::Node.new(params: basic_auth_params)
419
405
  @transfer_server_address = URI.parse(@api_node.params[:base_url]).host
@@ -431,7 +417,7 @@ module Aspera
431
417
  if @access_remote
432
418
  # NOTE: the filter "name", it's why we take the first one
433
419
  @previews_folder_entry = get_folder_entries(@access_key_self['root_file_id'], {name: @option_previews_folder}).first
434
- raise CliError, "Folder #{@option_previews_folder} does not exist on node. "\
420
+ raise Cli::Error, "Folder #{@option_previews_folder} does not exist on node. " \
435
421
  'Please create it in the storage root, or specify an alternate name.' if @previews_folder_entry.nil?
436
422
  else
437
423
  raise 'only local storage allowed in this mode' unless @access_key_self['storage']['type'].eql?('local')
@@ -440,9 +426,9 @@ module Aspera
440
426
  @local_storage_root = @local_storage_root[PVCL_LOCAL_STORAGE.length..-1] if @local_storage_root.start_with?(PVCL_LOCAL_STORAGE)
441
427
  # TODO: windows could have "C:" ?
442
428
  raise "not local storage: #{@local_storage_root}" unless @local_storage_root.start_with?('/')
443
- raise CliError, "Local storage root folder #{@local_storage_root} does not exist." unless File.directory?(@local_storage_root)
429
+ raise Cli::Error, "Local storage root folder #{@local_storage_root} does not exist." unless File.directory?(@local_storage_root)
444
430
  @local_preview_folder = File.join(@local_storage_root, @option_previews_folder)
445
- raise CliError, "Folder #{@local_preview_folder} does not exist locally. "\
431
+ raise Cli::Error, "Folder #{@local_preview_folder} does not exist locally. " \
446
432
  'Please create it, or specify an alternate name.' unless File.directory?(@local_preview_folder)
447
433
  # protection to avoid clash of file id for two different access keys
448
434
  marker_file = File.join(@local_preview_folder, AK_MARKER_FILE)
@@ -455,7 +441,7 @@ module Aspera
455
441
  end
456
442
  end
457
443
  end
458
- Aspera::Preview::FileTypes.instance.use_mimemagic = options.get_option(:mimemagic, is_type: :mandatory)
444
+ Aspera::Preview::FileTypes.instance.use_mimemagic = options.get_option(:mimemagic, mandatory: true)
459
445
  # check tools that are anyway required for all cases
460
446
  Aspera::Preview::Utils.check_tools(@skip_types)
461
447
  case command
@@ -473,19 +459,21 @@ module Aspera
473
459
  else
474
460
  @api_node.read("files/#{scan_id}")[:data]
475
461
  end
462
+ @filter_block = Aspera::Node.file_matcher_from_argument(options)
476
463
  scan_folder_files(folder_info, scan_path)
477
464
  return Main.result_status('scan finished')
478
465
  when :events, :trevents
466
+ @filter_block = Aspera::Node.file_matcher_from_argument(options)
479
467
  iteration_persistency = nil
480
- if options.get_option(:once_only, is_type: :mandatory)
468
+ if options.get_option(:once_only, mandatory: true)
481
469
  iteration_persistency = PersistencyActionOnce.new(
482
470
  manager: @agents[:persistency],
483
471
  data: [],
484
472
  id: IdGenerator.from_list([
485
473
  'preview_iteration',
486
474
  command.to_s,
487
- options.get_option(:url, is_type: :mandatory),
488
- options.get_option(:username, is_type: :mandatory)
475
+ options.get_option(:url, mandatory: true),
476
+ options.get_option(:username, mandatory: true)
489
477
  ]))
490
478
  end
491
479
  # call processing method specified by command line command
@@ -493,19 +481,23 @@ module Aspera
493
481
  return Main.result_status("#{command} finished")
494
482
  when :check
495
483
  return Main.result_status('Tools validated')
496
- when :test
497
- format = options.get_next_argument('format', expected: Aspera::Preview::Generator::PREVIEW_FORMATS)
484
+ when :test, :show
498
485
  source = options.get_next_argument('source file')
499
- dest = preview_filename(format, options.get_option(:case))
500
- g = Aspera::Preview::Generator.new(@gen_options, source, dest, @tmp_folder, nil)
501
- raise "cannot find file type for #{source}" if g.conversion_type.nil?
502
- raise "out format #{format} not supported" unless g.supported?
486
+ format = options.get_next_argument('format', expected: Aspera::Preview::Generator::PREVIEW_FORMATS, default: :png)
487
+ generated_file_path = preview_filename(format, options.get_option(:base))
488
+ g = Aspera::Preview::Generator.new(source, generated_file_path, @gen_options, @tmp_folder, nil)
503
489
  g.generate
504
- return Main.result_status("generated: #{dest}")
490
+ if command.eql?(:show)
491
+ terminal_options = options.get_option(:query, default: {}).symbolize_keys
492
+ Log.log.debug{"preview: #{generated_file_path}"}
493
+ formatter.display_status(Aspera::Preview::Terminal.build(File.read(generated_file_path), **terminal_options))
494
+ end
495
+ return Main.result_status("generated: #{generated_file_path}")
505
496
  else
506
497
  raise 'error'
507
498
  end
508
499
  ensure
500
+ Log.log.debug{"cleaning up temp folder #{@tmp_folder}"}
509
501
  FileUtils.rm_rf(@tmp_folder)
510
502
  end # execute_action
511
503
  end # Preview