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.
- checksums.yaml +4 -4
- checksums.yaml.gz.sig +0 -0
- data/CHANGELOG.md +81 -7
- data/CONTRIBUTING.md +22 -6
- data/README.md +2038 -1080
- data/bin/ascli +18 -9
- data/bin/asession +12 -14
- data/examples/dascli +1 -1
- data/examples/proxy.pac +1 -1
- data/examples/rubyc +24 -0
- data/lib/aspera/aoc.rb +219 -159
- data/lib/aspera/ascmd.rb +25 -14
- data/lib/aspera/cli/basic_auth_plugin.rb +12 -9
- data/lib/aspera/cli/error.rb +17 -0
- data/lib/aspera/cli/extended_value.rb +47 -12
- data/lib/aspera/cli/formatter.rb +260 -179
- data/lib/aspera/cli/hints.rb +80 -0
- data/lib/aspera/cli/main.rb +104 -156
- data/lib/aspera/cli/manager.rb +259 -209
- data/lib/aspera/cli/plugin.rb +123 -63
- data/lib/aspera/cli/plugins/alee.rb +2 -3
- data/lib/aspera/cli/plugins/aoc.rb +341 -261
- data/lib/aspera/cli/plugins/ats.rb +22 -21
- data/lib/aspera/cli/plugins/bss.rb +5 -5
- data/lib/aspera/cli/plugins/config.rb +578 -627
- data/lib/aspera/cli/plugins/console.rb +44 -6
- data/lib/aspera/cli/plugins/cos.rb +15 -17
- data/lib/aspera/cli/plugins/faspex.rb +114 -100
- data/lib/aspera/cli/plugins/faspex5.rb +411 -264
- data/lib/aspera/cli/plugins/node.rb +354 -259
- data/lib/aspera/cli/plugins/orchestrator.rb +61 -29
- data/lib/aspera/cli/plugins/preview.rb +82 -90
- data/lib/aspera/cli/plugins/server.rb +79 -32
- data/lib/aspera/cli/plugins/shares.rb +55 -42
- data/lib/aspera/cli/sync_actions.rb +68 -0
- data/lib/aspera/cli/transfer_agent.rb +66 -73
- data/lib/aspera/cli/transfer_progress.rb +74 -0
- data/lib/aspera/cli/version.rb +1 -1
- data/lib/aspera/colors.rb +12 -8
- data/lib/aspera/command_line_builder.rb +14 -11
- data/lib/aspera/cos_node.rb +3 -2
- data/lib/aspera/data/6 +0 -0
- data/lib/aspera/environment.rb +24 -9
- data/lib/aspera/fasp/agent_aspera.rb +126 -0
- data/lib/aspera/fasp/agent_base.rb +31 -77
- data/lib/aspera/fasp/agent_connect.rb +25 -21
- data/lib/aspera/fasp/agent_direct.rb +89 -103
- data/lib/aspera/fasp/agent_httpgw.rb +231 -149
- data/lib/aspera/fasp/agent_node.rb +41 -34
- data/lib/aspera/fasp/agent_trsdk.rb +75 -32
- data/lib/aspera/fasp/error_info.rb +4 -2
- data/lib/aspera/fasp/faux_file.rb +52 -0
- data/lib/aspera/fasp/installation.rb +53 -195
- data/lib/aspera/fasp/management.rb +244 -0
- data/lib/aspera/fasp/parameters.rb +71 -37
- data/lib/aspera/fasp/parameters.yaml +76 -8
- data/lib/aspera/fasp/products.rb +162 -0
- data/lib/aspera/fasp/resume_policy.rb +3 -3
- data/lib/aspera/fasp/transfer_spec.rb +7 -6
- data/lib/aspera/fasp/uri.rb +26 -24
- data/lib/aspera/faspex_gw.rb +2 -2
- data/lib/aspera/faspex_postproc.rb +2 -2
- data/lib/aspera/hash_ext.rb +14 -4
- data/lib/aspera/json_rpc.rb +49 -0
- data/lib/aspera/keychain/macos_security.rb +13 -13
- data/lib/aspera/line_logger.rb +23 -0
- data/lib/aspera/log.rb +58 -16
- data/lib/aspera/node.rb +157 -92
- data/lib/aspera/oauth.rb +37 -19
- data/lib/aspera/open_application.rb +4 -4
- data/lib/aspera/persistency_action_once.rb +1 -1
- data/lib/aspera/persistency_folder.rb +2 -2
- data/lib/aspera/preview/file_types.rb +4 -2
- data/lib/aspera/preview/generator.rb +22 -35
- data/lib/aspera/preview/options.rb +2 -0
- data/lib/aspera/preview/terminal.rb +73 -16
- data/lib/aspera/preview/utils.rb +21 -28
- data/lib/aspera/proxy_auto_config.js +2 -2
- data/lib/aspera/rest.rb +136 -68
- data/lib/aspera/rest_call_error.rb +1 -1
- data/lib/aspera/rest_error_analyzer.rb +15 -14
- data/lib/aspera/rest_errors_aspera.rb +37 -34
- data/lib/aspera/secret_hider.rb +18 -15
- data/lib/aspera/ssh.rb +5 -2
- data/lib/aspera/sync.rb +127 -119
- data/lib/aspera/temp_file_manager.rb +10 -3
- data/lib/aspera/web_auth.rb +10 -7
- data/lib/aspera/web_server_simple.rb +9 -4
- data.tar.gz.sig +0 -0
- metadata +34 -17
- metadata.gz.sig +0 -0
- data/docs/test_env.conf +0 -186
- data/lib/aspera/cli/listener/line_dump.rb +0 -19
- data/lib/aspera/cli/listener/logger.rb +0 -22
- data/lib/aspera/cli/listener/progress.rb +0 -50
- data/lib/aspera/cli/listener/progress_multi.rb +0 -84
- data/lib/aspera/cli/plugins/sync.rb +0 -44
- data/lib/aspera/data/7 +0 -0
- data/lib/aspera/fasp/listener.rb +0 -13
@@ -1,23 +1,55 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
-
require 'aspera/cli/
|
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.
|
13
|
-
options.
|
14
|
-
options.
|
15
|
-
options.
|
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,
|
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,
|
77
|
-
case options.get_option(:auth_style,
|
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
|
-
|
82
|
-
'login' => options.get_option(:username,
|
83
|
-
'password' => options.get_option(:password,
|
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,
|
88
|
-
password: options.get_option(:password,
|
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
|
-
|
126
|
-
|
127
|
-
result = call_ao('workflows_status',
|
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
|
-
#
|
153
|
-
|
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
|
189
|
+
call_params['synchronous'] = true if options.get_option(:synchronous, mandatory: true)
|
158
190
|
# expected result for synchro call ?
|
159
|
-
|
160
|
-
unless
|
191
|
+
result_location = options.get_option(:result)
|
192
|
+
unless result_location.nil?
|
161
193
|
result[:type] = :status
|
162
|
-
fields =
|
163
|
-
raise "Expects: work_step:result_name
|
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.
|
58
|
-
|
59
|
-
|
60
|
-
options.
|
61
|
-
|
62
|
-
|
63
|
-
|
64
|
-
|
65
|
-
options.
|
66
|
-
options.
|
67
|
-
options.
|
68
|
-
options.
|
69
|
-
options.
|
70
|
-
options.
|
71
|
-
options.
|
72
|
-
options.
|
73
|
-
options.
|
74
|
-
options.
|
75
|
-
|
76
|
-
|
77
|
-
|
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
|
-
|
82
|
-
|
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
|
-
|
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,
|
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 '
|
210
|
-
|
211
|
-
|
212
|
-
|
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
|
-
|
282
|
-
|
283
|
-
|
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
|
-
|
317
|
-
|
318
|
-
|
319
|
-
|
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
|
355
|
-
def scan_folder_files(top_entry,
|
356
|
-
|
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
|
-
|
359
|
-
scan_start = "#{scan_start}/" # unless scan_start.end_with?('/')
|
346
|
+
top_path = '/' + top_path.split('/').reject(&:empty?).join('/') + '/'
|
360
347
|
end
|
361
|
-
|
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
|
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 !
|
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
|
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
|
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
|
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,
|
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,
|
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,
|
488
|
-
options.get_option(:username,
|
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
|
-
|
500
|
-
|
501
|
-
|
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
|
-
|
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
|