aspera-cli 4.5.0 → 4.8.0

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 (104) hide show
  1. checksums.yaml +4 -4
  2. checksums.yaml.gz.sig +1 -0
  3. data/README.md +1894 -1574
  4. data/bin/ascli +21 -1
  5. data/bin/asession +38 -34
  6. data/docs/test_env.conf +14 -3
  7. data/examples/aoc.rb +17 -15
  8. data/examples/dascli +26 -0
  9. data/examples/faspex4.rb +42 -35
  10. data/examples/proxy.pac +1 -1
  11. data/examples/transfer.rb +38 -37
  12. data/lib/aspera/aoc.rb +245 -205
  13. data/lib/aspera/ascmd.rb +111 -90
  14. data/lib/aspera/ats_api.rb +16 -14
  15. data/lib/aspera/cli/basic_auth_plugin.rb +19 -18
  16. data/lib/aspera/cli/extended_value.rb +50 -39
  17. data/lib/aspera/cli/formater.rb +161 -135
  18. data/lib/aspera/cli/info.rb +18 -0
  19. data/lib/aspera/cli/listener/line_dump.rb +4 -2
  20. data/lib/aspera/cli/listener/logger.rb +3 -1
  21. data/lib/aspera/cli/listener/progress.rb +20 -21
  22. data/lib/aspera/cli/listener/progress_multi.rb +29 -31
  23. data/lib/aspera/cli/main.rb +194 -183
  24. data/lib/aspera/cli/manager.rb +213 -206
  25. data/lib/aspera/cli/plugin.rb +71 -49
  26. data/lib/aspera/cli/plugins/alee.rb +8 -7
  27. data/lib/aspera/cli/plugins/aoc.rb +675 -558
  28. data/lib/aspera/cli/plugins/ats.rb +116 -109
  29. data/lib/aspera/cli/plugins/bss.rb +35 -34
  30. data/lib/aspera/cli/plugins/config.rb +722 -542
  31. data/lib/aspera/cli/plugins/console.rb +28 -22
  32. data/lib/aspera/cli/plugins/cos.rb +28 -37
  33. data/lib/aspera/cli/plugins/faspex.rb +281 -227
  34. data/lib/aspera/cli/plugins/faspex5.rb +129 -84
  35. data/lib/aspera/cli/plugins/node.rb +426 -232
  36. data/lib/aspera/cli/plugins/orchestrator.rb +106 -98
  37. data/lib/aspera/cli/plugins/preview.rb +196 -191
  38. data/lib/aspera/cli/plugins/server.rb +131 -126
  39. data/lib/aspera/cli/plugins/shares.rb +49 -36
  40. data/lib/aspera/cli/plugins/sync.rb +27 -28
  41. data/lib/aspera/cli/transfer_agent.rb +84 -79
  42. data/lib/aspera/cli/version.rb +3 -1
  43. data/lib/aspera/colors.rb +37 -28
  44. data/lib/aspera/command_line_builder.rb +84 -63
  45. data/lib/aspera/cos_node.rb +68 -34
  46. data/lib/aspera/data_repository.rb +4 -2
  47. data/lib/aspera/environment.rb +61 -46
  48. data/lib/aspera/fasp/agent_base.rb +36 -31
  49. data/lib/aspera/fasp/agent_connect.rb +44 -37
  50. data/lib/aspera/fasp/agent_direct.rb +101 -104
  51. data/lib/aspera/fasp/agent_httpgw.rb +91 -90
  52. data/lib/aspera/fasp/agent_node.rb +36 -33
  53. data/lib/aspera/fasp/agent_trsdk.rb +28 -31
  54. data/lib/aspera/fasp/error.rb +3 -1
  55. data/lib/aspera/fasp/error_info.rb +81 -54
  56. data/lib/aspera/fasp/installation.rb +171 -151
  57. data/lib/aspera/fasp/listener.rb +2 -0
  58. data/lib/aspera/fasp/parameters.rb +105 -111
  59. data/lib/aspera/fasp/parameters.yaml +305 -249
  60. data/lib/aspera/fasp/resume_policy.rb +20 -20
  61. data/lib/aspera/fasp/transfer_spec.rb +27 -0
  62. data/lib/aspera/fasp/uri.rb +31 -29
  63. data/lib/aspera/faspex_gw.rb +95 -118
  64. data/lib/aspera/hash_ext.rb +12 -13
  65. data/lib/aspera/id_generator.rb +11 -9
  66. data/lib/aspera/keychain/encrypted_hash.rb +73 -57
  67. data/lib/aspera/keychain/macos_security.rb +27 -29
  68. data/lib/aspera/log.rb +40 -39
  69. data/lib/aspera/nagios.rb +24 -22
  70. data/lib/aspera/node.rb +38 -30
  71. data/lib/aspera/oauth.rb +217 -248
  72. data/lib/aspera/open_application.rb +9 -7
  73. data/lib/aspera/persistency_action_once.rb +15 -14
  74. data/lib/aspera/persistency_folder.rb +15 -18
  75. data/lib/aspera/preview/file_types.rb +266 -270
  76. data/lib/aspera/preview/generator.rb +94 -92
  77. data/lib/aspera/preview/image_error.png +0 -0
  78. data/lib/aspera/preview/options.rb +20 -17
  79. data/lib/aspera/preview/utils.rb +99 -102
  80. data/lib/aspera/preview/video_error.png +0 -0
  81. data/lib/aspera/{proxy_auto_config.erb.js → proxy_auto_config.js} +23 -31
  82. data/lib/aspera/proxy_auto_config.rb +114 -21
  83. data/lib/aspera/rest.rb +144 -142
  84. data/lib/aspera/rest_call_error.rb +3 -2
  85. data/lib/aspera/rest_error_analyzer.rb +31 -31
  86. data/lib/aspera/rest_errors_aspera.rb +18 -16
  87. data/lib/aspera/secret_hider.rb +68 -0
  88. data/lib/aspera/ssh.rb +20 -16
  89. data/lib/aspera/sync.rb +57 -54
  90. data/lib/aspera/temp_file_manager.rb +20 -14
  91. data/lib/aspera/timer_limiter.rb +10 -8
  92. data/lib/aspera/uri_reader.rb +14 -15
  93. data/lib/aspera/web_auth.rb +85 -80
  94. data.tar.gz.sig +0 -0
  95. metadata +169 -40
  96. metadata.gz.sig +2 -0
  97. data/bin/dascli +0 -13
  98. data/docs/Makefile +0 -63
  99. data/docs/README.erb.md +0 -4221
  100. data/docs/README.md +0 -13
  101. data/docs/diagrams.txt +0 -49
  102. data/docs/doc_tools.rb +0 -58
  103. data/lib/aspera/cli/plugins/shares2.rb +0 -114
  104. data/lib/aspera/fasp/default.rb +0 -17
@@ -1,8 +1,11 @@
1
+ # frozen_string_literal: true
2
+
1
3
  require 'aspera/cli/basic_auth_plugin'
2
4
  require 'aspera/preview/generator'
3
5
  require 'aspera/preview/options'
4
6
  require 'aspera/preview/utils'
5
7
  require 'aspera/preview/file_types'
8
+ require 'aspera/fasp/transfer_spec'
6
9
  require 'aspera/persistency_action_once'
7
10
  require 'aspera/node'
8
11
  require 'aspera/hash_ext'
@@ -16,88 +19,86 @@ module Aspera
16
19
  module Plugins
17
20
  class Preview < BasicAuthPlugin
18
21
  # special tag to identify transfers related to generator
19
- PREV_GEN_TAG='preview_generator'
22
+ PREV_GEN_TAG = 'preview_generator'
20
23
  # defined by node API: suffix for folder containing previews
21
- PREVIEW_FOLDER_SUFFIX='.asp-preview'
24
+ PREVIEW_FOLDER_SUFFIX = '.asp-preview'
22
25
  # basename of preview files
23
- PREVIEW_BASENAME='preview'
26
+ PREVIEW_BASENAME = 'preview'
24
27
  # subfolder in system tmp folder
25
- TMP_DIR_PREFIX='prev_tmp'
26
- DEFAULT_PREVIEWS_FOLDER='previews'
27
- AK_MARKER_FILE='.aspera_access_key'
28
- LOCAL_STORAGE_PCVL='file:///'
29
- LOG_LIMITER_SEC=30.0
30
- private_constant :PREV_GEN_TAG, :PREVIEW_FOLDER_SUFFIX, :PREVIEW_BASENAME, :TMP_DIR_PREFIX, :DEFAULT_PREVIEWS_FOLDER, :LOCAL_STORAGE_PCVL, :AK_MARKER_FILE, :LOG_LIMITER_SEC
28
+ TMP_DIR_PREFIX = 'prev_tmp'
29
+ DEFAULT_PREVIEWS_FOLDER = 'previews'
30
+ AK_MARKER_FILE = '.aspera_access_key'
31
+ LOCAL_STORAGE_PCVL = 'file:///'
32
+ LOG_LIMITER_SEC = 30.0
33
+ private_constant :PREV_GEN_TAG, :PREVIEW_FOLDER_SUFFIX, :PREVIEW_BASENAME, :TMP_DIR_PREFIX, :DEFAULT_PREVIEWS_FOLDER,
34
+ :LOCAL_STORAGE_PCVL, :AK_MARKER_FILE, :LOG_LIMITER_SEC
31
35
 
32
36
  # option_skip_format has special accessors
33
37
  attr_accessor :option_previews_folder
34
- attr_accessor :option_folder_reset_cache
35
- attr_accessor :option_skip_folders
36
- attr_accessor :option_overwrite
37
- attr_accessor :option_file_access
38
+ attr_accessor :option_folder_reset_cache, :option_skip_folders, :option_overwrite, :option_file_access
38
39
  def initialize(env)
39
40
  super(env)
40
- @skip_types=[]
41
- @default_transfer_spec=nil
41
+ @skip_types = []
42
+ @default_transfer_spec = nil
42
43
  # by default generate all supported formats (clone, as altered by options)
43
- @preview_formats_to_generate=Aspera::Preview::Generator::PREVIEW_FORMATS.clone
44
+ @preview_formats_to_generate = Aspera::Preview::Generator::PREVIEW_FORMATS.clone
44
45
  # options for generation
45
- @gen_options=Aspera::Preview::Options.new
46
+ @gen_options = Aspera::Preview::Options.new
46
47
  # used to trigger periodic processing
47
- @periodic=TimerLimiter.new(LOG_LIMITER_SEC)
48
+ @periodic = TimerLimiter.new(LOG_LIMITER_SEC)
48
49
  # link CLI options to gen_info attributes
49
- self.options.set_obj_attr(:skip_format,self,:option_skip_format,[]) # no skip
50
- self.options.set_obj_attr(:folder_reset_cache,self,:option_folder_reset_cache,:no)
51
- self.options.set_obj_attr(:skip_types,self,:option_skip_types)
52
- self.options.set_obj_attr(:previews_folder,self,:option_previews_folder,DEFAULT_PREVIEWS_FOLDER)
53
- self.options.set_obj_attr(:skip_folders,self,:option_skip_folders,[]) # no skip
54
- self.options.set_obj_attr(:overwrite,self,:option_overwrite,:mtime)
55
- self.options.set_obj_attr(:file_access,self,:option_file_access,:local)
56
- self.options.add_opt_list(:skip_format,Aspera::Preview::Generator::PREVIEW_FORMATS,'skip this preview format (multiple possible)')
57
- self.options.add_opt_list(:folder_reset_cache,[:no,:header,:read],'force detection of generated preview by refresh cache')
58
- self.options.add_opt_simple(:skip_types,'skip types in comma separated list')
59
- self.options.add_opt_simple(:previews_folder,'preview folder in storage root')
60
- self.options.add_opt_simple(:temp_folder,'path to temp folder')
61
- self.options.add_opt_simple(:skip_folders,'list of folder to skip')
62
- self.options.add_opt_simple(:case,'basename of output for for test')
63
- self.options.add_opt_simple(:scan_path,'subpath in folder id to start scan in (default=/)')
64
- self.options.add_opt_simple(:scan_id,'forder id in storage to start scan in, default is access key main folder id')
65
- self.options.add_opt_boolean(:mimemagic,'use Mime type detection of gem mimemagic')
66
- self.options.add_opt_list(:overwrite,[:always,:never,:mtime],'when to overwrite result file')
67
- self.options.add_opt_list(:file_access,[:local,:remote],'how to read and write files in repository')
68
- self.options.set_option(:temp_folder,Dir.tmpdir)
69
- self.options.set_option(:mimemagic,:false)
50
+ options.set_obj_attr(:skip_format,self,:option_skip_format,[]) # no skip
51
+ options.set_obj_attr(:folder_reset_cache,self,:option_folder_reset_cache,:no)
52
+ options.set_obj_attr(:skip_types,self,:option_skip_types)
53
+ options.set_obj_attr(:previews_folder,self,:option_previews_folder,DEFAULT_PREVIEWS_FOLDER)
54
+ options.set_obj_attr(:skip_folders,self,:option_skip_folders,[]) # no skip
55
+ options.set_obj_attr(:overwrite,self,:option_overwrite,:mtime)
56
+ options.set_obj_attr(:file_access,self,:option_file_access,:local)
57
+ options.add_opt_list(:skip_format,Aspera::Preview::Generator::PREVIEW_FORMATS,'skip this preview format (multiple possible)')
58
+ options.add_opt_list(:folder_reset_cache,%i[no header read],'force detection of generated preview by refresh cache')
59
+ options.add_opt_simple(:skip_types,'skip types in comma separated list')
60
+ options.add_opt_simple(:previews_folder,'preview folder in storage root')
61
+ options.add_opt_simple(:temp_folder,'path to temp folder')
62
+ options.add_opt_simple(:skip_folders,'list of folder to skip')
63
+ options.add_opt_simple(:case,'basename of output for for test')
64
+ options.add_opt_simple(:scan_path,'subpath in folder id to start scan in (default=/)')
65
+ options.add_opt_simple(:scan_id,'forder id in storage to start scan in, default is access key main folder id')
66
+ options.add_opt_boolean(:mimemagic,'use Mime type detection of gem mimemagic')
67
+ options.add_opt_list(:overwrite,%i[always never mtime],'when to overwrite result file')
68
+ options.add_opt_list(:file_access,%i[local remote],'how to read and write files in repository')
69
+ options.set_option(:temp_folder,Dir.tmpdir)
70
+ options.set_option(:mimemagic,false)
70
71
 
71
72
  # add other options for generator (and set default values)
72
73
  Aspera::Preview::Options::DESCRIPTIONS.each do |opt|
73
- self.options.set_obj_attr(opt[:name],@gen_options,opt[:name],opt[:default])
74
+ options.set_obj_attr(opt[:name],@gen_options,opt[:name],opt[:default])
74
75
  if opt.has_key?(:values)
75
- self.options.add_opt_list(opt[:name],opt[:values],opt[:description])
76
- elsif [:yes,:no].include?(opt[:default])
77
- self.options.add_opt_boolean(opt[:name],opt[:description])
76
+ options.add_opt_list(opt[:name],opt[:values],opt[:description])
77
+ elsif Cli::Manager::BOOLEAN_SIMPLE.include?(opt[:default])
78
+ options.add_opt_boolean(opt[:name],opt[:description])
78
79
  else
79
- self.options.add_opt_simple(opt[:name],opt[:description])
80
+ options.add_opt_simple(opt[:name],opt[:description])
80
81
  end
81
82
  end
82
83
 
83
- self.options.parse_options!
84
+ options.parse_options!
84
85
  raise 'skip_folder shall be an Array, use @json:[...]' unless @option_skip_folders.is_a?(Array)
85
- @tmp_folder=File.join(self.options.get_option(:temp_folder,:mandatory),"#{TMP_DIR_PREFIX}.#{SecureRandom.uuid}")
86
+ @tmp_folder = File.join(options.get_option(:temp_folder,is_type: :mandatory),"#{TMP_DIR_PREFIX}.#{SecureRandom.uuid}")
86
87
  FileUtils.mkdir_p(@tmp_folder)
87
88
  Log.log.debug("tmpdir: #{@tmp_folder}")
88
89
  end
89
90
 
90
91
  def option_skip_types=(value)
91
- @skip_types=[]
92
+ @skip_types = []
92
93
  value.split(',').each do |v|
93
- s=v.to_sym
94
+ s = v.to_sym
94
95
  raise "not supported: #{v}" unless Aspera::Preview::FileTypes::CONVERSION_TYPES.include?(s)
95
96
  @skip_types.push(s)
96
97
  end
97
98
  end
98
99
 
99
100
  def option_skip_types
100
- return @skip_types.map{|i|i.to_s}.join(',')
101
+ return @skip_types.map(&:to_s).join(',')
101
102
  end
102
103
 
103
104
  def option_skip_format=(value)
@@ -105,29 +106,29 @@ module Aspera
105
106
  end
106
107
 
107
108
  def option_skip_format
108
- return @preview_formats_to_generate.map{|i|i.to_s}.join(',')
109
+ return @preview_formats_to_generate.map(&:to_s).join(',')
109
110
  end
110
111
 
111
112
  # /files/id/files is normally cached in redis, but we can discard the cache
112
113
  # but /files/id is not cached
113
114
  def get_folder_entries(file_id,request_args=nil)
114
- headers={'Accept'=>'application/json'}
115
- headers.merge!({'X-Aspera-Cache-Control'=>'no-cache'}) if @option_folder_reset_cache.eql?(:header)
116
- return @api_node.call({:operation=>'GET',:subpath=>"files/#{file_id}/files",:headers=>headers,:url_params=>request_args})[:data]
115
+ headers = {'Accept' => 'application/json'}
116
+ headers['X-Aspera-Cache-Control'] = 'no-cache' if @option_folder_reset_cache.eql?(:header)
117
+ return @api_node.call({operation: 'GET',subpath: "files/#{file_id}/files",headers: headers,url_params: request_args})[:data]
117
118
  #return @api_node.read("files/#{file_id}/files",request_args)[:data]
118
119
  end
119
120
 
120
121
  # old version based on folders
121
122
  # @param iteration_persistency can be nil
122
123
  def process_trevents(iteration_persistency)
123
- events_filter={
124
- 'access_key'=>@access_key_self['id'],
125
- 'type'=>'download.ended'
124
+ events_filter = {
125
+ 'access_key' => @access_key_self['id'],
126
+ 'type' => 'download.ended'
126
127
  }
127
128
  # optionally add iteration token from persistency
128
- events_filter['iteration_token']=iteration_persistency.data.first unless iteration_persistency.nil?
129
+ events_filter['iteration_token'] = iteration_persistency.data.first unless iteration_persistency.nil?
129
130
  begin
130
- events=@api_node.read('events',events_filter)[:data]
131
+ events = @api_node.read('events',events_filter)[:data]
131
132
  rescue RestCallError => e
132
133
  if e.message.include?('Invalid iteration_token')
133
134
  Log.log.warn("Retrying without iteration token: #{e}")
@@ -138,24 +139,24 @@ module Aspera
138
139
  end
139
140
  return if events.empty?
140
141
  events.each do |event|
141
- if event['data']['direction'].eql?('receive') and
142
- event['data']['status'].eql?('completed') and
143
- event['data']['error_code'].eql?(0) and
142
+ if event['data']['direction'].eql?(Fasp::TransferSpec::DIRECTION_RECEIVE) &&
143
+ event['data']['status'].eql?('completed') &&
144
+ event['data']['error_code'].eql?(0) &&
144
145
  event['data'].dig('tags','aspera',PREV_GEN_TAG).nil?
145
- folder_id=event.dig('data','tags','aspera','node','file_id')
146
- folder_id||=event.dig('data','file_id')
146
+ folder_id = event.dig('data','tags','aspera','node','file_id')
147
+ folder_id ||= event.dig('data','file_id')
147
148
  if !folder_id.nil?
148
- folder_entry=@api_node.read("files/#{folder_id}")[:data] rescue nil
149
+ folder_entry = @api_node.read("files/#{folder_id}")[:data] rescue nil
149
150
  scan_folder_files(folder_entry) unless folder_entry.nil?
150
151
  end
151
152
  end
152
- if @periodic.trigger? or event.equal?(events.last)
153
- Log.log.info("Processed event #{event['id']}")
154
- # save checkpoint to avoid losing processing in case of error
155
- if !iteration_persistency.nil?
156
- iteration_persistency.data[0]=event['id'].to_s
157
- iteration_persistency.save
158
- end
153
+ # log/persist periodically or last one
154
+ next unless @periodic.trigger? || event.equal?(events.last)
155
+ Log.log.info("Processed event #{event['id']}")
156
+ # save checkpoint to avoid losing processing in case of error
157
+ if !iteration_persistency.nil?
158
+ iteration_persistency.data[0] = event['id'].to_s
159
+ iteration_persistency.save
159
160
  end
160
161
  end
161
162
  end
@@ -163,21 +164,21 @@ module Aspera
163
164
  # requests recent events on node api and process newly modified folders
164
165
  def process_events(iteration_persistency)
165
166
  # get new file creation by access key (TODO: what if file already existed?)
166
- events_filter={
167
- 'access_key'=>@access_key_self['id'],
168
- 'type'=>'file.*'
167
+ events_filter = {
168
+ 'access_key' => @access_key_self['id'],
169
+ 'type' => 'file.*'
169
170
  }
170
171
  # optionally add iteration token from persistency
171
- events_filter['iteration_token']=iteration_persistency.data.first unless iteration_persistency.nil?
172
- events=@api_node.read('events',events_filter)[:data]
172
+ events_filter['iteration_token'] = iteration_persistency.data.first unless iteration_persistency.nil?
173
+ events = @api_node.read('events',events_filter)[:data]
173
174
  return if events.empty?
174
175
  events.each do |event|
175
176
  # process only files
176
177
  if event.dig('data','type').eql?('file')
177
- file_entry=@api_node.read("files/#{event['data']['id']}")[:data] rescue nil
178
- if !file_entry.nil? and
178
+ file_entry = @api_node.read("files/#{event['data']['id']}")[:data] rescue nil
179
+ if !file_entry.nil? &&
179
180
  @option_skip_folders.select{|d|file_entry['path'].start_with?(d)}.empty?
180
- file_entry['parent_file_id']=event['data']['parent_file_id']
181
+ file_entry['parent_file_id'] = event['data']['parent_file_id']
181
182
  if event['types'].include?('file.deleted')
182
183
  Log.log.error('TODO'.red)
183
184
  end
@@ -186,81 +187,83 @@ module Aspera
186
187
  end
187
188
  end
188
189
  end
189
- if @periodic.trigger? or event.equal?(events.last)
190
- Log.log.info("Processing event #{event['id']}")
191
- # save checkpoint to avoid losing processing in case of error
192
- if !iteration_persistency.nil?
193
- iteration_persistency.data[0]=event['id'].to_s
194
- iteration_persistency.save
195
- end
190
+ # log/persist periodically or last one
191
+ next unless @periodic.trigger? || event.equal?(events.last)
192
+ Log.log.info("Processing event #{event['id']}")
193
+ # save checkpoint to avoid losing processing in case of error
194
+ if !iteration_persistency.nil?
195
+ iteration_persistency.data[0] = event['id'].to_s
196
+ iteration_persistency.save
196
197
  end
197
198
  end
198
199
  end
199
200
 
200
201
  def do_transfer(direction,folder_id,source_filename,destination='/')
201
- raise "error" if destination.nil? and direction.eql?('receive')
202
+ raise 'error' if destination.nil? && direction.eql?(Fasp::TransferSpec::DIRECTION_RECEIVE)
202
203
  if @default_transfer_spec.nil?
203
204
  # make a dummy call to get some default transfer parameters
204
- res=@api_node.create('files/upload_setup',{'transfer_requests'=>[{'transfer_request'=>{'paths'=>[{}],'destination_root'=>'/'}}]})
205
- template_ts=res[:data]['transfer_specs'].first['transfer_spec']
205
+ res = @api_node.create('files/upload_setup',{'transfer_requests' => [{'transfer_request' => {'paths' => [{}],'destination_root' => '/'}}]})
206
+ template_ts = res[:data]['transfer_specs'].first['transfer_spec']
206
207
  # get ports, anyway that should be 33001 for both. add remote_user ?
207
- @default_transfer_spec=['ssh_port','fasp_port'].inject({}){|h,e|h[e]=template_ts[e];h}
208
- if ! @default_transfer_spec['remote_user'].eql?(Aspera::Fasp::Default::ACCESS_KEY_TRANSFER_USER)
209
- Log.log.warn("remote_user shall be xfer")
210
- @default_transfer_spec['remote_user']=Aspera::Fasp::Default::ACCESS_KEY_TRANSFER_USER
208
+ @default_transfer_spec = %w[ssh_port fasp_port].each_with_object({}){|e,h|h[e] = template_ts[e];}
209
+ if !@default_transfer_spec['remote_user'].eql?(Aspera::Fasp::TransferSpec::ACCESS_KEY_TRANSFER_USER)
210
+ Log.log.warn('remote_user shall be xfer')
211
+ @default_transfer_spec['remote_user'] = Aspera::Fasp::TransferSpec::ACCESS_KEY_TRANSFER_USER
211
212
  end
212
- Aspera::Node::set_ak_basic_token(@default_transfer_spec,@access_key_self['id'],self.options.get_option(:password,:mandatory))
213
+ Aspera::Node.set_ak_basic_token(@default_transfer_spec,@access_key_self['id'],options.get_option(:password,is_type: :mandatory))
213
214
  # note: we use the same address for ascp than for node api instead of the one from upload_setup
214
215
  # TODO: configurable ? useful ?
215
- @default_transfer_spec['remote_host']=@transfer_server_address
216
+ @default_transfer_spec['remote_host'] = @transfer_server_address
216
217
  end
217
- tspec=@default_transfer_spec.merge({
218
- 'direction' => direction,
219
- 'paths' => [{'source'=>source_filename}],
220
- 'tags' => { 'aspera' => {
221
- PREV_GEN_TAG => true,
222
- 'node' => {
223
- 'access_key' => @access_key_self['id'],
224
- 'file_id' => folder_id }}}
218
+ tspec = @default_transfer_spec.merge({
219
+ 'direction' => direction,
220
+ 'paths' => [{'source' => source_filename}],
221
+ 'tags' => { 'aspera' => {
222
+ PREV_GEN_TAG => true,
223
+ 'node' => {
224
+ 'access_key' => @access_key_self['id'],
225
+ 'file_id' => folder_id }}}
225
226
  })
226
227
  # force destination
227
228
  # tspec['destination_root']=destination
228
- self.transfer.option_transfer_spec_deep_merge({'destination_root'=>destination})
229
- Main.result_transfer(self.transfer.start(tspec,{:src=>:node_gen4}))
229
+ transfer.option_transfer_spec_deep_merge({'destination_root' => destination})
230
+ Main.result_transfer(transfer.start(tspec,{src: :node_gen4}))
230
231
  end
231
232
 
232
- def get_infos_local(gen_infos,entry,local_entry_preview_dir)
233
- local_original_filepath=File.join(@local_storage_root,entry['path'])
234
- original_mtime=File.mtime(local_original_filepath)
233
+ def get_infos_local(gen_infos,entry)
234
+ local_original_filepath = File.join(@local_storage_root,entry['path'])
235
+ original_mtime = File.mtime(local_original_filepath)
235
236
  # out
236
- local_entry_preview_dir.replace(File.join(@local_preview_folder, entry_preview_folder_name(entry)))
237
+ local_entry_preview_dir = File.join(@local_preview_folder, entry_preview_folder_name(entry))
237
238
  gen_infos.each do |gen_info|
238
- gen_info[:src]=local_original_filepath
239
- gen_info[:dst]=File.join(local_entry_preview_dir, gen_info[:base_dest])
240
- gen_info[:preview_exist]=File.exist?(gen_info[:dst])
241
- gen_info[:preview_newer_than_original] = (gen_info[:preview_exist] and (File.mtime(gen_info[:dst])>original_mtime))
239
+ gen_info[:src] = local_original_filepath
240
+ gen_info[:dst] = File.join(local_entry_preview_dir, gen_info[:base_dest])
241
+ gen_info[:preview_exist] = File.exist?(gen_info[:dst])
242
+ gen_info[:preview_newer_than_original] = (gen_info[:preview_exist] && (File.mtime(gen_info[:dst]) > original_mtime))
242
243
  end
244
+ return local_entry_preview_dir
243
245
  end
244
246
 
245
- def get_infos_remote(gen_infos,entry,local_entry_preview_dir)
247
+ def get_infos_remote(gen_infos,entry)
246
248
  #Log.log.debug(">>>> get_infos_remote #{entry}".red)
247
249
  # store source directly here
248
- local_original_filepath=File.join(@tmp_folder,entry['name'])
250
+ local_original_filepath = File.join(@tmp_folder,entry['name'])
249
251
  #original_mtime=DateTime.parse(entry['modified_time'])
250
252
  # out: where previews are generated
251
- local_entry_preview_dir.replace(File.join(@tmp_folder,entry_preview_folder_name(entry)))
252
- file_info=@api_node.read("files/#{entry['id']}")[:data]
253
+ local_entry_preview_dir = File.join(@tmp_folder,entry_preview_folder_name(entry))
254
+ file_info = @api_node.read("files/#{entry['id']}")[:data]
253
255
  #TODO: this does not work because previews is hidden in api (gen4)
254
- #this_preview_folder_entries=get_folder_entries(@previews_folder_entry['id'],{:name=>@entry_preview_folder_name})
256
+ #this_preview_folder_entries=get_folder_entries(@previews_folder_entry['id'],{name: @entry_preview_folder_name})
255
257
  # TODO: use gen3 api to list files and get date
256
258
  gen_infos.each do |gen_info|
257
- gen_info[:src]=local_original_filepath
258
- gen_info[:dst]=File.join(local_entry_preview_dir, gen_info[:base_dest])
259
+ gen_info[:src] = local_original_filepath
260
+ gen_info[:dst] = File.join(local_entry_preview_dir, gen_info[:base_dest])
259
261
  # TODO: use this_preview_folder_entries (but it's hidden)
260
- gen_info[:preview_exist]=file_info.has_key?('preview')
262
+ gen_info[:preview_exist] = file_info.has_key?('preview')
261
263
  # TODO: get change time and compare, useful ?
262
264
  gen_info[:preview_newer_than_original] = gen_info[:preview_exist]
263
265
  end
266
+ return local_entry_preview_dir
264
267
  end
265
268
 
266
269
  # defined by node api
@@ -269,30 +272,24 @@ module Aspera
269
272
  end
270
273
 
271
274
  def preview_filename(preview_format,filename=nil)
272
- filename||=PREVIEW_BASENAME
273
- return "#{filename}.#{preview_format.to_s}"
275
+ filename ||= PREVIEW_BASENAME
276
+ return "#{filename}.#{preview_format}"
274
277
  end
275
278
 
276
279
  # generate preview files for one folder entry (file) if necessary
277
280
  # entry must contain "parent_file_id" if remote.
278
281
  def generate_preview(entry)
279
- #Log.log.debug(">>>> #{entry}".red)
280
- # folder where previews will be generated for this particular entry
281
- local_entry_preview_dir=String.new
282
282
  # prepare generic information
283
- gen_infos=@preview_formats_to_generate.map do |preview_format|
283
+ gen_infos = @preview_formats_to_generate.map do |preview_format|
284
284
  {
285
- :preview_format => preview_format,
286
- :base_dest => preview_filename(preview_format)
285
+ preview_format: preview_format,
286
+ base_dest: preview_filename(preview_format)
287
287
  }
288
288
  end
289
289
  # lets gather some infos on possibly existing previews
290
290
  # it depends if files access locally or remotely
291
- if @access_remote
292
- get_infos_remote(gen_infos,entry,local_entry_preview_dir)
293
- else # direct local file system access
294
- get_infos_local(gen_infos,entry,local_entry_preview_dir)
295
- end
291
+ # folder where previews will be generated for this particular entry
292
+ local_entry_preview_dir = @access_remote ? get_infos_remote(gen_infos,entry) : get_infos_local(gen_infos,entry)
296
293
  # here we have the status on preview files
297
294
  # let's find if they need generation
298
295
  gen_infos.select! do |gen_info|
@@ -310,7 +307,7 @@ module Aspera
310
307
  end
311
308
  end
312
309
  # need generator for further checks
313
- gen_info[:generator]=Aspera::Preview::Generator.new(@gen_options,gen_info[:src],gen_info[:dst],@tmp_folder,entry['content_type'])
310
+ gen_info[:generator] = Aspera::Preview::Generator.new(@gen_options,gen_info[:src],gen_info[:dst],@tmp_folder,entry['content_type'])
314
311
  # get conversion_type (if known) and check if supported
315
312
  next false unless gen_info[:generator].supported?
316
313
  # shall we skip it ?
@@ -324,7 +321,7 @@ module Aspera
324
321
  if @access_remote
325
322
  raise 'missing parent_file_id in entry' if entry['parent_file_id'].nil?
326
323
  # download original file to temp folder
327
- do_transfer('receive',entry['parent_file_id'],entry['name'],@tmp_folder)
324
+ do_transfer(Fasp::TransferSpec::DIRECTION_RECEIVE,entry['parent_file_id'],entry['name'],@tmp_folder)
328
325
  end
329
326
  Log.log.info("source: #{entry['id']}: #{entry['path']})")
330
327
  gen_infos.each do |gen_info|
@@ -332,7 +329,7 @@ module Aspera
332
329
  end
333
330
  if @access_remote
334
331
  # upload
335
- do_transfer('send',@previews_folder_entry['id'],local_entry_preview_dir)
332
+ do_transfer(Fasp::TransferSpec::DIRECTION_SEND,@previews_folder_entry['id'],local_entry_preview_dir)
336
333
  # cleanup after upload
337
334
  FileUtils.rm_rf(local_entry_preview_dir)
338
335
  File.delete(File.join(@tmp_folder,entry['name']))
@@ -341,8 +338,8 @@ module Aspera
341
338
  if @option_folder_reset_cache.eql?(:read)
342
339
  @api_node.read("files/#{entry['id']}")
343
340
  end
344
- rescue => e
345
- Log.log.error("#{e.message}")
341
+ rescue StandardError => e
342
+ Log.log.error("Ignore: #{e.message}")
346
343
  Log.log.debug(e.backtrace.join("\n").red)
347
344
  end # generate_preview
348
345
 
@@ -351,20 +348,20 @@ module Aspera
351
348
  def scan_folder_files(top_entry,scan_start=nil)
352
349
  if !scan_start.nil?
353
350
  # canonical path: start with / and ends with /
354
- scan_start='/'+scan_start.split('/').select{|i|!i.empty?}.join('/')
355
- scan_start="#{scan_start}/" #unless scan_start.end_with?('/')
351
+ scan_start = '/' + scan_start.split('/').reject(&:empty?).join('/')
352
+ scan_start = "#{scan_start}/" #unless scan_start.end_with?('/')
356
353
  end
357
- filter_block=Aspera::Node.file_matcher(options.get_option(:value,:optional))
354
+ filter_block = Aspera::Node.file_matcher(options.get_option(:value))
358
355
  Log.log.debug("scan: #{top_entry} : #{scan_start}".green)
359
356
  # don't use recursive call, use list instead
360
- entries_to_process=[top_entry]
357
+ entries_to_process = [top_entry]
361
358
  while !entries_to_process.empty?
362
- entry=entries_to_process.shift
359
+ entry = entries_to_process.shift
363
360
  # process this entry only if it is within the scan_start
364
- entry_path_with_slash=entry['path']
361
+ entry_path_with_slash = entry['path']
365
362
  Log.log.info("processing entry #{entry_path_with_slash}") if @periodic.trigger?
366
- entry_path_with_slash="#{entry_path_with_slash}/" unless entry_path_with_slash.end_with?('/')
367
- if !scan_start.nil? and !scan_start.start_with?(entry_path_with_slash) and !entry_path_with_slash.start_with?(scan_start)
363
+ entry_path_with_slash = "#{entry_path_with_slash}/" unless entry_path_with_slash.end_with?('/')
364
+ if !scan_start.nil? && !scan_start.start_with?(entry_path_with_slash) && !entry_path_with_slash.start_with?(scan_start)
368
365
  Log.log.debug("#{entry['path']} folder (skip start)".bg_red)
369
366
  next
370
367
  end
@@ -385,93 +382,101 @@ module Aspera
385
382
  else
386
383
  Log.log.debug("#{entry['path']} folder".green)
387
384
  # get folder content
388
- folder_entries=get_folder_entries(entry['id'])
385
+ folder_entries = get_folder_entries(entry['id'])
389
386
  # process all items in current folder
390
387
  folder_entries.each do |folder_entry|
391
388
  # add path for older versions of ES
392
389
  if !folder_entry.has_key?('path')
393
- folder_entry['path']=entry_path_with_slash+folder_entry['name']
390
+ folder_entry['path'] = entry_path_with_slash + folder_entry['name']
394
391
  end
395
- folder_entry['parent_file_id']=entry['id']
392
+ folder_entry['parent_file_id'] = entry['id']
396
393
  entries_to_process.push(folder_entry)
397
394
  end
398
395
  end
399
396
  else
400
397
  Log.log.warn("unknown entry type: #{entry['type']}")
401
398
  end
402
- rescue => e
399
+ rescue StandardError => e
403
400
  Log.log.warn("An error occured: #{e}, ignoring")
404
401
  end
405
402
  end
406
403
  end
407
404
 
408
- ACTIONS=[:scan,:events,:trevents,:check,:test]
405
+ ACTIONS = %i[scan events trevents check test].freeze
409
406
 
410
407
  def execute_action
411
- command=self.options.get_next_command(ACTIONS)
412
- unless [:check,:test].include?(command)
408
+ command = options.get_next_command(ACTIONS)
409
+ unless %i[check test].include?(command)
413
410
  # this will use node api
414
- @api_node=basic_auth_api
415
- @transfer_server_address=URI.parse(@api_node.params[:base_url]).host
411
+ @api_node = basic_auth_api
412
+ @transfer_server_address = URI.parse(@api_node.params[:base_url]).host
416
413
  # get current access key
417
- @access_key_self=@api_node.read('access_keys/self')[:data]
414
+ @access_key_self = @api_node.read('access_keys/self')[:data]
418
415
  # TODO: check events is activated here:
419
416
  # note that docroot is good to look at as well
420
- node_info=@api_node.read('info')[:data]
417
+ node_info = @api_node.read('info')[:data]
421
418
  Log.log.debug("root: #{node_info['docroot']}")
422
- @access_remote=@option_file_access.eql?(:remote)
419
+ @access_remote = @option_file_access.eql?(:remote)
423
420
  Log.log.debug("remote: #{@access_remote}")
424
421
  Log.log.debug("access key info: #{@access_key_self}")
425
422
  #TODO: can the previews folder parameter be read from node api ?
426
- @option_skip_folders.push('/'+@option_previews_folder)
423
+ @option_skip_folders.push('/' + @option_previews_folder)
427
424
  if @access_remote
428
425
  # note the filter "name", it's why we take the first one
429
- @previews_folder_entry=get_folder_entries(@access_key_self['root_file_id'],{:name=>@option_previews_folder}).first
430
- raise CliError,"Folder #{@option_previews_folder} does not exist on node. Please create it in the storage root, or specify an alternate name." if @previews_folder_entry.nil?
426
+ @previews_folder_entry = get_folder_entries(@access_key_self['root_file_id'],{name: @option_previews_folder}).first
427
+ raise CliError,"Folder #{@option_previews_folder} does not exist on node. "\
428
+ 'Please create it in the storage root, or specify an alternate name.' if @previews_folder_entry.nil?
431
429
  else
432
- raise "only local storage allowed in this mode" unless @access_key_self['storage']['type'].eql?('local')
433
- @local_storage_root=@access_key_self['storage']['path']
430
+ raise 'only local storage allowed in this mode' unless @access_key_self['storage']['type'].eql?('local')
431
+ @local_storage_root = @access_key_self['storage']['path']
434
432
  #TODO: option to override @local_storage_root='xxx'
435
- @local_storage_root=@local_storage_root[LOCAL_STORAGE_PCVL.length..-1] if @local_storage_root.start_with?(LOCAL_STORAGE_PCVL)
433
+ @local_storage_root = @local_storage_root[LOCAL_STORAGE_PCVL.length..-1] if @local_storage_root.start_with?(LOCAL_STORAGE_PCVL)
436
434
  #TODO: windows could have "C:" ?
437
435
  raise "not local storage: #{@local_storage_root}" unless @local_storage_root.start_with?('/')
438
436
  raise CliError,"Local storage root folder #{@local_storage_root} does not exist." unless File.directory?(@local_storage_root)
439
- @local_preview_folder=File.join(@local_storage_root,@option_previews_folder)
440
- raise CliError,"Folder #{@local_preview_folder} does not exist locally. Please create it, or specify an alternate name." unless File.directory?(@local_preview_folder)
437
+ @local_preview_folder = File.join(@local_storage_root,@option_previews_folder)
438
+ raise CliError,"Folder #{@local_preview_folder} does not exist locally. "\
439
+ 'Please create it, or specify an alternate name.' unless File.directory?(@local_preview_folder)
441
440
  # protection to avoid clash of file id for two different access keys
442
- marker_file=File.join(@local_preview_folder,AK_MARKER_FILE)
441
+ marker_file = File.join(@local_preview_folder,AK_MARKER_FILE)
443
442
  Log.log.debug("marker file: #{marker_file}")
444
443
  if File.exist?(marker_file)
445
- ak=File.read(marker_file)
444
+ ak = File.read(marker_file).chomp
446
445
  raise "mismatch access key in #{marker_file}: contains #{ak}, using #{@access_key_self['id']}" unless @access_key_self['id'].eql?(ak)
447
446
  else
448
447
  File.write(marker_file,@access_key_self['id'])
449
448
  end
450
449
  end
451
450
  end
452
- Aspera::Preview::FileTypes.instance.use_mimemagic = self.options.get_option(:mimemagic,:mandatory)
451
+ Aspera::Preview::FileTypes.instance.use_mimemagic = options.get_option(:mimemagic,is_type: :mandatory)
453
452
  case command
454
453
  when :scan
455
- scan_path=self.options.get_option(:scan_path,:optional)
456
- scan_id=self.options.get_option(:scan_id,:optional)
454
+ scan_path = options.get_option(:scan_path)
455
+ scan_id = options.get_option(:scan_id)
457
456
  # by default start at root
458
- folder_info=if scan_id.nil?
459
- { 'id' => @access_key_self['root_file_id'],
460
- 'name' => '/',
461
- 'type' => 'folder',
462
- 'path' => '/' }
463
- else
464
- @api_node.read("files/#{scan_id}")[:data]
465
- end
457
+ folder_info =
458
+ if scan_id.nil?
459
+ { 'id' => @access_key_self['root_file_id'],
460
+ 'name' => '/',
461
+ 'type' => 'folder',
462
+ 'path' => '/' }
463
+ else
464
+ @api_node.read("files/#{scan_id}")[:data]
465
+ end
466
466
  scan_folder_files(folder_info,scan_path)
467
467
  return Main.result_status('scan finished')
468
468
  when :events,:trevents
469
- iteration_persistency=nil
470
- if self.options.get_option(:once_only,:mandatory)
471
- iteration_persistency=PersistencyActionOnce.new(
472
- manager: @agents[:persistency],
473
- data: [],
474
- id: IdGenerator.from_list(['preview_iteration',command.to_s,self.options.get_option(:url,:mandatory),self.options.get_option(:username,:mandatory)]))
469
+ iteration_persistency = nil
470
+ if options.get_option(:once_only,is_type: :mandatory)
471
+ iteration_persistency = PersistencyActionOnce.new(
472
+ manager: @agents[:persistency],
473
+ data: [],
474
+ id: IdGenerator.from_list([
475
+ 'preview_iteration',
476
+ command.to_s,
477
+ options.get_option(:url,is_type: :mandatory),
478
+ options.get_option(:username,is_type: :mandatory)
479
+ ]))
475
480
  end
476
481
  # call processing method specified by command line command
477
482
  send("process_#{command}",iteration_persistency)
@@ -480,16 +485,16 @@ module Aspera
480
485
  Aspera::Preview::Utils.check_tools(@skip_types)
481
486
  return Main.result_status('tools validated')
482
487
  when :test
483
- format = self.options.get_next_argument('format',Aspera::Preview::Generator::PREVIEW_FORMATS)
484
- source = self.options.get_next_argument('source file')
485
- dest=preview_filename(format,self.options.get_option(:case,:optional))
486
- g=Aspera::Preview::Generator.new(@gen_options,source,dest,@tmp_folder,nil)
488
+ format = options.get_next_argument('format',expected: Aspera::Preview::Generator::PREVIEW_FORMATS)
489
+ source = options.get_next_argument('source file')
490
+ dest = preview_filename(format,options.get_option(:case))
491
+ g = Aspera::Preview::Generator.new(@gen_options,source,dest,@tmp_folder,nil)
487
492
  raise "cannot find file type for #{source}" if g.conversion_type.nil?
488
493
  raise "out format #{format} not supported" unless g.supported?
489
494
  g.generate
490
495
  return Main.result_status("generated: #{dest}")
491
496
  else
492
- raise "error"
497
+ raise 'error'
493
498
  end
494
499
  ensure
495
500
  FileUtils.rm_rf(@tmp_folder)