aspera-cli 4.15.0 → 4.16.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (80) hide show
  1. checksums.yaml +4 -4
  2. checksums.yaml.gz.sig +0 -0
  3. data/BUGS.md +29 -3
  4. data/CHANGELOG.md +292 -228
  5. data/CONTRIBUTING.md +69 -18
  6. data/README.md +1102 -952
  7. data/bin/ascli +13 -31
  8. data/bin/asession +3 -1
  9. data/examples/dascli +2 -2
  10. data/lib/aspera/aoc.rb +28 -33
  11. data/lib/aspera/ascmd.rb +3 -6
  12. data/lib/aspera/assert.rb +45 -0
  13. data/lib/aspera/cli/extended_value.rb +5 -5
  14. data/lib/aspera/cli/formatter.rb +26 -13
  15. data/lib/aspera/cli/hints.rb +4 -3
  16. data/lib/aspera/cli/main.rb +16 -3
  17. data/lib/aspera/cli/manager.rb +45 -36
  18. data/lib/aspera/cli/plugin.rb +20 -13
  19. data/lib/aspera/cli/plugins/aoc.rb +103 -73
  20. data/lib/aspera/cli/plugins/ats.rb +4 -3
  21. data/lib/aspera/cli/plugins/config.rb +114 -119
  22. data/lib/aspera/cli/plugins/cos.rb +2 -2
  23. data/lib/aspera/cli/plugins/faspex.rb +23 -19
  24. data/lib/aspera/cli/plugins/faspex5.rb +75 -43
  25. data/lib/aspera/cli/plugins/node.rb +28 -15
  26. data/lib/aspera/cli/plugins/orchestrator.rb +4 -2
  27. data/lib/aspera/cli/plugins/preview.rb +9 -7
  28. data/lib/aspera/cli/plugins/server.rb +6 -3
  29. data/lib/aspera/cli/plugins/shares.rb +30 -26
  30. data/lib/aspera/cli/sync_actions.rb +9 -9
  31. data/lib/aspera/cli/transfer_agent.rb +21 -14
  32. data/lib/aspera/cli/transfer_progress.rb +2 -3
  33. data/lib/aspera/cli/version.rb +1 -1
  34. data/lib/aspera/command_line_builder.rb +13 -11
  35. data/lib/aspera/cos_node.rb +3 -2
  36. data/lib/aspera/coverage.rb +22 -0
  37. data/lib/aspera/data_repository.rb +33 -2
  38. data/lib/aspera/environment.rb +4 -2
  39. data/lib/aspera/fasp/{agent_aspera.rb → agent_alpha.rb} +29 -39
  40. data/lib/aspera/fasp/agent_base.rb +17 -7
  41. data/lib/aspera/fasp/agent_direct.rb +88 -84
  42. data/lib/aspera/fasp/agent_httpgw.rb +4 -3
  43. data/lib/aspera/fasp/agent_node.rb +3 -2
  44. data/lib/aspera/fasp/agent_trsdk.rb +79 -37
  45. data/lib/aspera/fasp/installation.rb +51 -12
  46. data/lib/aspera/fasp/management.rb +11 -6
  47. data/lib/aspera/fasp/parameters.rb +53 -47
  48. data/lib/aspera/fasp/resume_policy.rb +7 -5
  49. data/lib/aspera/fasp/sync.rb +273 -0
  50. data/lib/aspera/fasp/transfer_spec.rb +10 -8
  51. data/lib/aspera/fasp/uri.rb +2 -2
  52. data/lib/aspera/faspex_gw.rb +11 -8
  53. data/lib/aspera/faspex_postproc.rb +6 -5
  54. data/lib/aspera/id_generator.rb +3 -1
  55. data/lib/aspera/json_rpc.rb +10 -8
  56. data/lib/aspera/keychain/encrypted_hash.rb +46 -11
  57. data/lib/aspera/keychain/macos_security.rb +15 -13
  58. data/lib/aspera/log.rb +4 -3
  59. data/lib/aspera/nagios.rb +7 -2
  60. data/lib/aspera/node.rb +17 -16
  61. data/lib/aspera/node_simulator.rb +214 -0
  62. data/lib/aspera/oauth.rb +22 -19
  63. data/lib/aspera/persistency_action_once.rb +13 -14
  64. data/lib/aspera/persistency_folder.rb +3 -2
  65. data/lib/aspera/preview/file_types.rb +53 -267
  66. data/lib/aspera/preview/generator.rb +7 -5
  67. data/lib/aspera/preview/terminal.rb +14 -5
  68. data/lib/aspera/preview/utils.rb +8 -7
  69. data/lib/aspera/proxy_auto_config.rb +6 -3
  70. data/lib/aspera/rest.rb +29 -13
  71. data/lib/aspera/rest_error_analyzer.rb +1 -0
  72. data/lib/aspera/rest_errors_aspera.rb +2 -0
  73. data/lib/aspera/secret_hider.rb +5 -2
  74. data/lib/aspera/ssh.rb +10 -8
  75. data/lib/aspera/temp_file_manager.rb +1 -1
  76. data/lib/aspera/web_server_simple.rb +2 -1
  77. data.tar.gz.sig +0 -0
  78. metadata +96 -45
  79. metadata.gz.sig +0 -0
  80. data/lib/aspera/sync.rb +0 -219
@@ -2,6 +2,7 @@
2
2
 
3
3
  require 'aspera/log'
4
4
  require 'singleton'
5
+ require 'mime/types'
5
6
 
6
7
  module Aspera
7
8
  module Preview
@@ -11,266 +12,41 @@ module Aspera
11
12
  # values for conversion_type : input format
12
13
  CONVERSION_TYPES = %i[image office pdf plaintext video].freeze
13
14
 
14
- # define how files are processed based on mime type
15
+ # special cases for mime types
15
16
  # spellchecker:disable
16
17
  SUPPORTED_MIME_TYPES = {
17
- 'application/json' => :plaintext,
18
- 'application/mac-binhex40' => :office,
19
- 'application/msword' => :office,
20
- 'application/pdf' => :pdf,
21
- 'application/postscript' => :image,
22
- 'application/rtf' => :office,
23
- 'application/vnd.3gpp.pic-bw-small' => :image,
24
- 'application/vnd.hp-hpgl' => :image,
25
- 'application/vnd.hp-pcl' => :image,
26
- 'application/vnd.lotus-wordpro' => :office,
27
- 'application/vnd.mobius.msl' => :image,
28
- 'application/vnd.mophun.certificate' => :image,
29
- 'application/vnd.ms-excel' => :office,
30
- 'application/vnd.ms-excel.sheet.binary.macroenabled.12' => :office,
31
- 'application/vnd.ms-excel.sheet.macroenabled.12' => :office,
32
- 'application/vnd.ms-excel.template.macroenabled.12' => :office,
33
- 'application/vnd.ms-powerpoint' => :office,
34
- 'application/vnd.ms-powerpoint.presentation.macroenabled.12' => :office,
35
- 'application/vnd.ms-powerpoint.template.macroenabled.12' => :office,
36
- 'application/vnd.ms-word.document.macroenabled.12' => :office,
37
- 'application/vnd.ms-word.template.macroenabled.12' => :office,
38
- 'application/vnd.ms-works' => :office,
39
- 'application/vnd.oasis.opendocument.chart' => :office,
40
- 'application/vnd.oasis.opendocument.formula' => :office,
41
- 'application/vnd.oasis.opendocument.graphics' => :office,
42
- 'application/vnd.oasis.opendocument.graphics-template' => :office,
43
- 'application/vnd.oasis.opendocument.presentation' => :office,
44
- 'application/vnd.oasis.opendocument.presentation-template' => :office,
45
- 'application/vnd.oasis.opendocument.spreadsheet' => :office,
46
- 'application/vnd.oasis.opendocument.spreadsheet-template' => :office,
47
- 'application/vnd.oasis.opendocument.text' => :office,
48
- 'application/vnd.oasis.opendocument.text-template' => :office,
49
- 'application/vnd.openxmlformats-officedocument.presentationml.presentation' => :office,
50
- 'application/vnd.openxmlformats-officedocument.presentationml.slideshow' => :office,
51
- 'application/vnd.openxmlformats-officedocument.presentationml.template' => :office,
52
- 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet' => :office,
53
- 'application/vnd.openxmlformats-officedocument.spreadsheetml.template' => :office,
54
- 'application/vnd.openxmlformats-officedocument.wordprocessingml.document' => :office,
55
- 'application/vnd.openxmlformats-officedocument.wordprocessingml.template' => :office,
56
- 'application/vnd.palm' => :office,
57
- 'application/vnd.sun.xml.calc' => :office,
58
- 'application/vnd.sun.xml.calc.template' => :office,
59
- 'application/vnd.sun.xml.draw' => :office,
60
- 'application/vnd.sun.xml.draw.template' => :office,
61
- 'application/vnd.sun.xml.impress' => :office,
62
- 'application/vnd.sun.xml.impress.template' => :office,
63
- 'application/vnd.sun.xml.math' => :office,
64
- 'application/vnd.sun.xml.writer' => :office,
65
- 'application/vnd.sun.xml.writer.template' => :office,
66
- 'application/vnd.wordperfect' => :office,
67
- 'application/x-abiword' => :office,
68
- 'application/x-director' => :image,
69
- 'application/x-font-type1' => :image,
70
- 'application/x-msmetafile' => :image,
71
- 'application/x-mspublisher' => :office,
72
- 'application/x-xfig' => :image,
73
- 'audio/ogg' => :video,
74
- 'font/ttf' => :image,
75
- 'image/bmp' => :image,
76
- 'image/cgm' => :image,
77
- 'image/gif' => :image,
78
- 'image/jpeg' => :image,
79
- 'image/png' => :image,
80
- 'image/sgi' => :image,
81
- 'image/svg+xml' => :image,
82
- 'image/tiff' => :image,
83
- 'image/vnd.adobe.photoshop' => :image,
84
- 'image/vnd.djvu' => :image,
85
- 'image/vnd.dxf' => :office,
86
- 'image/vnd.fpx' => :image,
87
- 'image/vnd.ms-photo' => :image,
88
- 'image/vnd.wap.wbmp' => :image,
89
- 'image/webp' => :image,
90
- 'image/x-cmx' => :office,
91
- 'image/x-freehand' => :office,
92
- 'image/x-icon' => :image,
93
- 'image/x-mrsid-image' => :image,
94
- 'image/x-pcx' => :image,
95
- 'image/x-pict' => :office,
96
- 'image/x-portable-anymap' => :image,
97
- 'image/x-portable-bitmap' => :image,
98
- 'image/x-portable-graymap' => :image,
99
- 'image/x-portable-pixmap' => :image,
100
- 'image/x-rgb' => :image,
101
- 'image/x-tga' => :image,
102
- 'image/x-xbitmap' => :image,
103
- 'image/x-xpixmap' => :image,
104
- 'image/x-xwindowdump' => :image,
105
- 'text/csv' => :office,
106
- 'text/html' => :office,
107
- 'text/plain' => :plaintext,
108
- 'text/troff' => :image,
109
- 'video/h261' => :video,
110
- 'video/h263' => :video,
111
- 'video/h264' => :video,
112
- 'video/mp4' => :video,
113
- 'video/mpeg' => :video,
114
- 'video/quicktime' => :video,
115
- 'video/x-flv' => :video,
116
- 'video/x-m4v' => :video,
117
- 'video/x-matroska' => :video,
118
- 'video/x-mng' => :image,
119
- 'video/x-ms-wmv' => :video,
120
- 'video/x-msvideo' => :video}.freeze
18
+ 'application/json' => :plaintext,
19
+ 'text/plain' => :plaintext,
20
+ 'application/pdf' => :pdf,
21
+ 'audio/ogg' => :video,
22
+ 'application/mxf' => :video,
23
+ 'application/mac-binhex40' => :office,
24
+ 'application/msword' => :office,
25
+ 'application/rtf' => :office,
26
+ 'application/x-abiword' => :office,
27
+ 'application/x-mspublisher' => :office,
28
+ 'image/vnd.dxf' => :office,
29
+ 'image/x-cmx' => :office,
30
+ 'image/x-freehand' => :office,
31
+ 'image/x-pict' => :office,
32
+ 'text/csv' => :office,
33
+ 'text/html' => :office,
34
+ 'application/dicom' => :image,
35
+ 'application/postscript' => :image,
36
+ 'application/vnd.3gpp.pic-bw-small' => :image,
37
+ 'application/vnd.hp-hpgl' => :image,
38
+ 'application/vnd.hp-pcl' => :image,
39
+ 'application/vnd.mobius.msl' => :image,
40
+ 'application/vnd.mophun.certificate' => :image,
41
+ 'application/x-director' => :image,
42
+ 'application/x-font-type1' => :image,
43
+ 'application/x-msmetafile' => :image,
44
+ 'application/x-xfig' => :image,
45
+ 'font/ttf' => :image,
46
+ 'text/troff' => :image,
47
+ 'video/x-mng' => :image}.freeze
121
48
 
122
- # this is a way to add support for extensions that are otherwise not known by node api (mime type)
123
- SUPPORTED_EXTENSIONS = {
124
- 'aai' => :image,
125
- 'art' => :image,
126
- 'arw' => :image,
127
- 'avs' => :image,
128
- 'bmp2' => :image,
129
- 'bmp3' => :image,
130
- 'bpg' => :image,
131
- 'cals' => :image,
132
- 'cdr' => :office,
133
- 'cin' => :image,
134
- 'clipboard' => :image,
135
- 'cmyk' => :image,
136
- 'cmyka' => :image,
137
- 'cr2' => :image,
138
- 'crw' => :image,
139
- 'cur' => :image,
140
- 'cut' => :image,
141
- 'cwk' => :office,
142
- 'dbf' => :office,
143
- 'dcm' => :image,
144
- 'dcx' => :image,
145
- 'dds' => :image,
146
- 'dib' => :image,
147
- 'dif' => :office,
148
- 'divx' => :video,
149
- 'dng' => :image,
150
- 'docx' => :office,
151
- 'dpx' => :image,
152
- 'epdf' => :image,
153
- 'epi' => :image,
154
- 'eps2' => :image,
155
- 'eps3' => :image,
156
- 'epsf' => :image,
157
- 'epsi' => :image,
158
- 'ept' => :image,
159
- 'exr' => :image,
160
- 'fax' => :image,
161
- 'fb2' => :office,
162
- 'fits' => :image,
163
- 'fodg' => :office,
164
- 'fodp' => :office,
165
- 'fods' => :office,
166
- 'fodt' => :office,
167
- 'gplt' => :image,
168
- 'gray' => :image,
169
- 'hdr' => :image,
170
- 'hpw' => :office,
171
- 'hrz' => :image,
172
- 'info' => :image,
173
- 'inline' => :image,
174
- 'j2c' => :image,
175
- 'j2k' => :image,
176
- 'jbig' => :image,
177
- 'jng' => :image,
178
- 'jp2' => :image,
179
- 'jpt' => :image,
180
- 'jxr' => :image,
181
- 'key' => :office,
182
- 'log' => :plaintext,
183
- 'mat' => :image,
184
- 'mcw' => :office,
185
- 'met' => :office,
186
- 'miff' => :image,
187
- 'mml' => :office,
188
- 'mono' => :image,
189
- 'mpr' => :image,
190
- 'mrsid' => :image,
191
- 'mrw' => :image,
192
- 'mtv' => :image,
193
- 'mvg' => :image,
194
- 'mw' => :office,
195
- 'mwd' => :office,
196
- 'mxf' => :video,
197
- 'nef' => :image,
198
- 'numbers' => :office,
199
- 'orf' => :image,
200
- 'otb' => :image,
201
- 'p7' => :image,
202
- 'pages' => :office,
203
- 'palm' => :image,
204
- 'pam' => :image,
205
- 'pcd' => :image,
206
- 'pcds' => :image,
207
- 'pdf' => :pdf,
208
- 'pef' => :image,
209
- 'picon' => :image,
210
- 'pict' => :image,
211
- 'pix' => :image,
212
- 'pm' => :office,
213
- 'pm6' => :office,
214
- 'pmd' => :office,
215
- 'png00' => :image,
216
- 'png24' => :image,
217
- 'png32' => :image,
218
- 'png48' => :image,
219
- 'png64' => :image,
220
- 'png8' => :image,
221
- 'ps2' => :image,
222
- 'ps3' => :image,
223
- 'ptif' => :image,
224
- 'pwp' => :image,
225
- 'rad' => :image,
226
- 'raf' => :image,
227
- 'rfg' => :image,
228
- 'rgba' => :image,
229
- 'rla' => :image,
230
- 'rle' => :image,
231
- 'sct' => :image,
232
- 'sfw' => :image,
233
- 'sgf' => :office,
234
- 'sgv' => :office,
235
- 'slk' => :office,
236
- 'sparse-color' => :image,
237
- 'sun' => :image,
238
- 'svm' => :office,
239
- 'sylk' => :office,
240
- 'tim' => :image,
241
- 'txt' => :plaintext,
242
- 'uil' => :image,
243
- 'uof' => :office,
244
- 'uop' => :office,
245
- 'uos' => :office,
246
- 'uot' => :office,
247
- 'uyvy' => :image,
248
- 'vds' => :office,
249
- 'vdx' => :office,
250
- 'vicar' => :image,
251
- 'viff' => :image,
252
- 'vsdx' => :office,
253
- 'webm' => :video,
254
- 'wb2' => :office,
255
- 'wk1' => :office,
256
- 'wk3' => :office,
257
- 'wn' => :office,
258
- 'wpg' => :image,
259
- 'wq1' => :office,
260
- 'wq2' => :office,
261
- 'x' => :image,
262
- 'x3f' => :image,
263
- 'xcf' => :image,
264
- 'xlk' => :office,
265
- 'xlsx' => :office,
266
- 'xls' => :office,
267
- 'ycbcr' => :image,
268
- 'ycbcra' => :image,
269
- 'yuv' => :image,
270
- 'zabw' => :office}.freeze
271
- # spellchecker:enable
272
-
273
- private_constant :SUPPORTED_MIME_TYPES, :SUPPORTED_EXTENSIONS
49
+ private_constant :SUPPORTED_MIME_TYPES
274
50
 
275
51
  # @attr use_mimemagic [bool] true to use mimemagic to determine real mime type based on file content
276
52
  attr_accessor :use_mimemagic
@@ -279,8 +55,18 @@ module Aspera
279
55
  @use_mimemagic = false
280
56
  end
281
57
 
58
+ # @param mimetype [String] mime type
59
+ # @return file type, one of enum CONVERSION_TYPES
60
+ def mime_to_type(mimetype)
61
+ return SUPPORTED_MIME_TYPES[mimetype] if SUPPORTED_MIME_TYPES.key?(mimetype)
62
+ return :office if mimetype.start_with?('application/vnd.')
63
+ return :video if mimetype.start_with?('video/')
64
+ return :image if mimetype.start_with?('image/')
65
+ return nil
66
+ end
67
+
282
68
  # use mime magic to find mime type based on file content (magic numbers)
283
- def mime_from_file(filepath)
69
+ def file_to_mime(filepath)
284
70
  # moved here, as `mimemagic` can cause installation issues
285
71
  require 'mimemagic'
286
72
  require 'mimemagic/version'
@@ -288,7 +74,7 @@ module Aspera
288
74
  # check magic number inside file (empty string if not found)
289
75
  detected_mime = MimeMagic.by_magic(File.open(filepath)).to_s
290
76
  # check extension only
291
- if !SUPPORTED_MIME_TYPES.key?(detected_mime)
77
+ if mime_to_type(detected_mime).nil?
292
78
  Log.log.debug{"no conversion for #{detected_mime}, trying extension"}
293
79
  detected_mime = MimeMagic.by_extension(File.extname(filepath)).to_s
294
80
  end
@@ -298,18 +84,18 @@ module Aspera
298
84
  end
299
85
 
300
86
  # @param filepath [String] full path to file
301
- # @param mimetype [String] provided by node api
87
+ # @param mimetype [String] provided by node API
302
88
  # @return file type, one of enum CONVERSION_TYPES
303
89
  # @raise [RuntimeError] if no conversion type found
304
90
  def conversion_type(filepath, mimetype)
305
91
  Log.log.debug{"conversion_type(#{filepath},m=#{mimetype},t=#{@use_mimemagic})"}
306
92
  # 1- get type from provided mime type, using local mapping
307
- conversion_type = SUPPORTED_MIME_TYPES[mimetype] if !mimetype.nil?
93
+ conversion_type = mime_to_type(mimetype) if !mimetype.nil?
308
94
  # 2- else, from computed mime type (if available)
309
95
  if conversion_type.nil? && @use_mimemagic
310
- detected_mime = mime_from_file(filepath)
96
+ detected_mime = file_to_mime(filepath)
311
97
  if !detected_mime.nil?
312
- conversion_type = SUPPORTED_MIME_TYPES[detected_mime]
98
+ conversion_type = mime_to_type(detected_mime)
313
99
  if !mimetype.nil?
314
100
  if mimetype.eql?(detected_mime)
315
101
  Log.log.debug('matching mime type per magic number')
@@ -321,10 +107,10 @@ module Aspera
321
107
  end
322
108
  end
323
109
  # 3- else, from extensions, using local mapping
324
- extension = File.extname(filepath.downcase)[1..-1]
325
- conversion_type = SUPPORTED_EXTENSIONS[extension] if conversion_type.nil?
326
- raise "no conversion type found for extension #{extension}" if conversion_type.nil?
327
- Log.log.debug{"conversion_type(#{extension}): #{conversion_type.class.name} [#{conversion_type}]"}
110
+ mime_by_ext = MIME::Types.of(File.basename(filepath)).first
111
+ conversion_type = mime_to_type(mime_by_ext.to_s) if conversion_type.nil? && !mime_by_ext.nil?
112
+ raise "no conversion type found for #{File.basename(filepath)}" if conversion_type.nil?
113
+ Log.log.trace1{"conversion_type(#{File.basename(filepath)}): #{conversion_type.class.name} [#{conversion_type}]"}
328
114
  return conversion_type
329
115
  end
330
116
  end
@@ -8,6 +8,8 @@ require 'open3'
8
8
  require 'aspera/preview/options'
9
9
  require 'aspera/preview/utils'
10
10
  require 'aspera/preview/file_types'
11
+ require 'aspera/log'
12
+ require 'aspera/assert'
11
13
 
12
14
  module Aspera
13
15
  module Preview
@@ -52,7 +54,7 @@ module Aspera
52
54
  end
53
55
  @processing_method = @processing_method.to_sym
54
56
  Log.log.debug{"method: #{@processing_method}"}
55
- raise "no processing know for #{conversion_type} -> #{@preview_format_sym}" unless respond_to?(@processing_method, true)
57
+ assert(respond_to?(@processing_method, true)){"no processing know for #{conversion_type} -> #{@preview_format_sym}"}
56
58
  end
57
59
 
58
60
  # create preview as specified in constructor
@@ -86,7 +88,7 @@ module Aspera
86
88
  # @param total_count of parts
87
89
  # @param index of part (start at 1)
88
90
  def get_offset(duration, start_offset, total_count, index)
89
- raise 'duration must be Float' unless duration.is_a?(Float)
91
+ assert_type(duration, Float){'duration'}
90
92
  return start_offset + ((index - 1) * (duration - start_offset) / total_count)
91
93
  end
92
94
 
@@ -149,10 +151,10 @@ module Aspera
149
151
  # do a simple re-encoding
150
152
  def convert_video_to_mp4_using_reencode
151
153
  options = @options.reencode_ffmpeg
152
- raise 'reencode_ffmpeg must be a Hash' unless options.is_a?(Hash)
154
+ assert_type(options, Hash){'reencode_ffmpeg'}
153
155
  options.each do |k, v|
154
- raise "Key not supported: #{k}. Use keys: #{FFMPEG_OPTIONS_LIST.join(',')}" unless FFMPEG_OPTIONS_LIST.include?(k)
155
- raise "Value for #{k} must be Array" unless v.is_a?(Array)
156
+ assert_values(k, FFMPEG_OPTIONS_LIST){'key'}
157
+ assert_type(v, Array){k}
156
158
  end
157
159
  Utils.ffmpeg(
158
160
  in_f: @source_file_path,
@@ -2,7 +2,6 @@
2
2
 
3
3
  # cspell:words Magick MAGICKCORE ITERM mintty winsize termcap
4
4
 
5
- require 'rmagick' # https://rmagick.github.io/index.html
6
5
  require 'rainbow'
7
6
  require 'io/console'
8
7
  module Aspera
@@ -10,8 +9,6 @@ module Aspera
10
9
  # Display a picture in the terminal, either using coloured characters or iTerm2
11
10
  class Terminal
12
11
  # Rainbow only supports 8-bit colors
13
- # quantum depth is 8 or 16, see: `convert xc: -format "%q" info:`
14
- SHIFT_FOR_8_BIT = Magick::MAGICKCORE_QUANTUM_DEPTH - 8
15
12
  # env vars to detect terminal type
16
13
  TERM_ENV_VARS = %w[TERM_PROGRAM LC_TERMINAL].freeze
17
14
  # terminal names that support iTerm2 image display
@@ -19,7 +16,7 @@ module Aspera
19
16
  # TODO: retrieve terminal font ratio using some termcap ?
20
17
  # ratio = font height / font width
21
18
  DEFAULT_FONT_RATIO = 32.0 / 14.0
22
- private_constant :SHIFT_FOR_8_BIT, :TERM_ENV_VARS, :ITERM_NAMES, :DEFAULT_FONT_RATIO
19
+ private_constant :TERM_ENV_VARS, :ITERM_NAMES, :DEFAULT_FONT_RATIO
23
20
  class << self
24
21
  # @return [String] the image as text, or the iTerm2 escape sequence
25
22
  # @param blob [String] the image as a binary string
@@ -29,6 +26,16 @@ module Aspera
29
26
  # @param font_ratio [Float] ratio = font height / font width
30
27
  def build(blob, reserve: 3, text: false, double: true, font_ratio: DEFAULT_FONT_RATIO)
31
28
  return iterm_display_image(blob) if iterm_supported? && !text
29
+ begin
30
+ # do not require statically, as the package is optional
31
+ require 'rmagick' # https://rmagick.github.io/index.html
32
+ rescue LoadError => e
33
+ Log.log.error('Install missing gem: gem install rmagick')
34
+ # fallback to iterm, if supported
35
+ return iterm_display_image(blob) if iterm_supported?
36
+ Log.log.error('Cant display picture.')
37
+ raise e
38
+ end
32
39
  image = Magick::ImageList.new.from_blob(blob)
33
40
  (term_rows, term_columns) = IO.console.winsize
34
41
  term_rows -= reserve
@@ -36,11 +43,13 @@ module Aspera
36
43
  fit_term_ratio = [term_rows / image.rows.to_f, term_columns / image.columns.to_f].min
37
44
  height_ratio = double ? 2.0 : 1.0
38
45
  image = image.scale((image.columns * fit_term_ratio * font_ratio).to_i, (image.rows * fit_term_ratio * height_ratio).to_i)
46
+ # quantum depth is 8 or 16, see: `convert xc: -format "%q" info:`
47
+ shift_for_8_bit = Magick::MAGICKCORE_QUANTUM_DEPTH - 8
39
48
  # get all pixel colors, adjusted for Rainbow
40
49
  pixel_colors = []
41
50
  image.each_pixel do |pixel, col, row|
42
51
  pixel_rgb = [pixel.red, pixel.green, pixel.blue]
43
- pixel_rgb = pixel_rgb.map { |color| color >> SHIFT_FOR_8_BIT } unless SHIFT_FOR_8_BIT.eql?(0)
52
+ pixel_rgb = pixel_rgb.map { |color| color >> shift_for_8_bit } unless shift_for_8_bit.eql?(0)
44
53
  # init 2-dim array
45
54
  pixel_colors[row] ||= []
46
55
  pixel_colors[row][col] = pixel_rgb
@@ -1,10 +1,11 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  # cspell:ignore ffprobe optipng unoconv
4
+ require 'aspera/log'
5
+ require 'aspera/assert'
4
6
  require 'English'
5
7
  require 'tmpdir'
6
8
  require 'fileutils'
7
- require 'aspera/log'
8
9
  require 'open3'
9
10
 
10
11
  module Aspera
@@ -31,7 +32,7 @@ module Aspera
31
32
  tools_to_check.delete(:unoconv) if skip_types.include?(:office)
32
33
  # Check for binaries
33
34
  tools_to_check.each do |command_sym|
34
- external_command(command_sym, ['-h'], log_error: false)
35
+ external_command(command_sym, ['-h'], check_code: false)
35
36
  rescue Errno::ENOENT => e
36
37
  raise "missing #{command_sym} binary: #{e}"
37
38
  rescue
@@ -42,13 +43,13 @@ module Aspera
42
43
  # execute external command
43
44
  # one could use "system", but we would need to redirect stdout/err
44
45
  # @return true if su
45
- def external_command(command_sym, command_args, log_error: true)
46
- raise "unexpected command #{command_sym}" unless EXTERNAL_TOOLS.include?(command_sym)
46
+ def external_command(command_sym, command_args, check_code: true)
47
+ assert_values(command_sym, EXTERNAL_TOOLS){'command'}
47
48
  # build command line, and quote special characters
48
49
  command_line = command_args.clone.unshift(command_sym).map{|i| shell_quote(i.to_s)}.join(' ')
49
50
  Log.log.debug{"cmd=#{command_line}".blue}
50
51
  stdout, stderr, status = Open3.capture3(command_line)
51
- if log_error && !status.success?
52
+ if check_code && !status.success?
52
53
  Log.log.error{"status: #{status}"}
53
54
  Log.log.error{"stdout: #{stdout}"}
54
55
  Log.log.error{"stderr: #{stderr}"}
@@ -58,7 +59,7 @@ module Aspera
58
59
  end
59
60
 
60
61
  def ffmpeg(a)
61
- raise 'error: hash expected' unless a.is_a?(Hash)
62
+ assert_type(a, Hash)
62
63
  # input_file,input_args,output_file,output_args
63
64
  a[:gl_p] ||= [
64
65
  '-y', # overwrite output without asking
@@ -66,7 +67,7 @@ module Aspera
66
67
  ]
67
68
  a[:in_p] ||= []
68
69
  a[:out_p] ||= []
69
- raise "wrong params (#{a.keys.sort})" unless %i[gl_p in_f in_p out_f out_p].eql?(a.keys.sort)
70
+ assert(%i[gl_p in_f in_p out_f out_p].eql?(a.keys.sort)){"wrong params (#{a.keys.sort})"}
70
71
  external_command(:ffmpeg, [a[:gl_p], a[:in_p], '-i', a[:in_f], a[:out_p], a[:out_f]].flatten)
71
72
  end
72
73
 
@@ -1,5 +1,7 @@
1
1
  # frozen_string_literal: true
2
2
 
3
+ require 'aspera/log'
4
+ require 'aspera/assert'
3
5
  require 'uri'
4
6
  require 'resolv'
5
7
 
@@ -9,7 +11,7 @@ module URI
9
11
  alias_method :find_proxy_orig, :find_proxy
10
12
  class << self
11
13
  def register_proxy_finder
12
- raise 'mandatory block missing' unless Kernel.block_given?
14
+ assert(block_given?)
13
15
  # overload the method in URI : call user's provided block and fallback to original method
14
16
  define_method(:find_proxy) {|env_vars=ENV| yield(to_s) || find_proxy_orig(env_vars)}
15
17
  end
@@ -107,11 +109,12 @@ END_OF_JAVASCRIPT
107
109
  parts = item.strip.split
108
110
  case parts.shift
109
111
  when 'DIRECT'
110
- raise 'DIRECT has no param' unless parts.empty?
112
+ assert(parts.empty?){'DIRECT has no param'}
111
113
  Log.log.debug('ignoring proxy DIRECT')
112
114
  when 'PROXY'
113
115
  addr_port = parts.shift
114
- raise 'PROXY shall have one param' unless addr_port.is_a?(String) && parts.empty?
116
+ assert_type(addr_port, String)
117
+ assert(parts.empty?){'PROXY shall have one param'}
115
118
  begin
116
119
  # PAC proxy addresses are <host>:<port>
117
120
  if /:[0-9]+$/.match?(addr_port)