aspera-cli 4.25.1 → 4.25.2
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.
- checksums.yaml +4 -4
- checksums.yaml.gz.sig +0 -0
- data/CHANGELOG.md +46 -1
- data/CONTRIBUTING.md +6 -11
- data/README.md +31 -9742
- data/bin/asession +111 -88
- data/lib/aspera/agent/connect.rb +1 -1
- data/lib/aspera/agent/desktop.rb +1 -1
- data/lib/aspera/agent/direct.rb +19 -18
- data/lib/aspera/agent/node.rb +1 -1
- data/lib/aspera/api/aoc.rb +25 -8
- data/lib/aspera/api/node.rb +16 -14
- data/lib/aspera/ascp/installation.rb +32 -51
- data/lib/aspera/assert.rb +1 -1
- data/lib/aspera/cli/extended_value.rb +1 -0
- data/lib/aspera/cli/formatter.rb +0 -4
- data/lib/aspera/cli/hints.rb +11 -4
- data/lib/aspera/cli/main.rb +3 -6
- data/lib/aspera/cli/manager.rb +8 -4
- data/lib/aspera/cli/plugins/aoc.rb +11 -14
- data/lib/aspera/cli/plugins/base.rb +1 -1
- data/lib/aspera/cli/plugins/config.rb +50 -48
- data/lib/aspera/cli/plugins/factory.rb +2 -2
- data/lib/aspera/cli/plugins/faspex5.rb +4 -3
- data/lib/aspera/cli/plugins/preview.rb +6 -11
- data/lib/aspera/cli/transfer_agent.rb +2 -2
- data/lib/aspera/cli/version.rb +1 -1
- data/lib/aspera/environment.rb +30 -16
- data/lib/aspera/faspex_gw.rb +1 -1
- data/lib/aspera/faspex_postproc.rb +16 -10
- data/lib/aspera/hash_ext.rb +8 -0
- data/lib/aspera/log.rb +3 -4
- data/lib/aspera/markdown.rb +17 -0
- data/lib/aspera/oauth/base.rb +1 -1
- data/lib/aspera/oauth/web.rb +1 -1
- data/lib/aspera/preview/generator.rb +9 -9
- data/lib/aspera/rest_call_error.rb +16 -8
- data/lib/aspera/rest_error_analyzer.rb +1 -1
- data/lib/aspera/transfer/resumer.rb +2 -2
- data/lib/aspera/yaml.rb +49 -0
- data.tar.gz.sig +0 -0
- metadata +16 -2
- metadata.gz.sig +0 -0
- data/release_notes.md +0 -8
|
@@ -27,8 +27,9 @@ module Aspera
|
|
|
27
27
|
# :reek:UncommunicativeMethodName
|
|
28
28
|
def do_POST(request, response)
|
|
29
29
|
Log.log.debug{"request=#{request.path}"}
|
|
30
|
+
Log.log.debug{"query=#{request.query}"}
|
|
30
31
|
begin
|
|
31
|
-
#
|
|
32
|
+
# Only accept requests on the root
|
|
32
33
|
if !request.path.start_with?(@parameters[:root])
|
|
33
34
|
response.status = 400
|
|
34
35
|
response['Content-Type'] = Rest::MIME_JSON
|
|
@@ -48,16 +49,21 @@ module Aspera
|
|
|
48
49
|
Log.log.debug{"script=#{script_path}"}
|
|
49
50
|
webhook_parameters = JSON.parse(request.body)
|
|
50
51
|
Log.dump(:webhook_parameters, webhook_parameters)
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
#
|
|
56
|
-
|
|
57
|
-
post_proc_pid =
|
|
52
|
+
if request.query.key?('lambda')
|
|
53
|
+
# Code can throw exception, source code must return a lambda
|
|
54
|
+
Environment.secure_eval(File.read(script_path), __FILE__, __LINE__).call(webhook_parameters)
|
|
55
|
+
else
|
|
56
|
+
# env expects only strings
|
|
57
|
+
environment = webhook_parameters.each_with_object({}){ |(k, v), h| h[k] = v.to_s}
|
|
58
|
+
post_proc_pid = Environment.secure_execute(script_path, mode: :background, env: environment)
|
|
59
|
+
Timeout.timeout(@parameters[:timeout_seconds]) do
|
|
60
|
+
# "wait" for process to avoid zombie
|
|
61
|
+
Process.wait(post_proc_pid)
|
|
62
|
+
post_proc_pid = nil
|
|
63
|
+
end
|
|
64
|
+
process_status = $CHILD_STATUS
|
|
65
|
+
raise "script #{script_path} failed with code #{process_status.exitstatus}" if !process_status.success? && @parameters[:fail_on_error]
|
|
58
66
|
end
|
|
59
|
-
process_status = $CHILD_STATUS
|
|
60
|
-
raise "script #{script_path} failed with code #{process_status.exitstatus}" if !process_status.success? && @parameters[:fail_on_error]
|
|
61
67
|
response.status = 200
|
|
62
68
|
response.content_type = Rest::MIME_JSON
|
|
63
69
|
response.body = JSON.generate({status: 'success', script: script_path, exit_code: process_status.exitstatus})
|
data/lib/aspera/hash_ext.rb
CHANGED
|
@@ -26,6 +26,10 @@ unless Hash.method_defined?(:symbolize_keys)
|
|
|
26
26
|
def symbolize_keys
|
|
27
27
|
return transform_keys(&:to_sym)
|
|
28
28
|
end
|
|
29
|
+
|
|
30
|
+
def symbolize_keys!
|
|
31
|
+
return transform_keys!(&:to_sym)
|
|
32
|
+
end
|
|
29
33
|
end
|
|
30
34
|
end
|
|
31
35
|
|
|
@@ -35,5 +39,9 @@ unless Hash.method_defined?(:stringify_keys)
|
|
|
35
39
|
def stringify_keys
|
|
36
40
|
return transform_keys(&:to_s)
|
|
37
41
|
end
|
|
42
|
+
|
|
43
|
+
def stringify_keys!
|
|
44
|
+
return transform_keys!(&:to_s)
|
|
45
|
+
end
|
|
38
46
|
end
|
|
39
47
|
end
|
data/lib/aspera/log.rb
CHANGED
|
@@ -174,11 +174,10 @@ module Aspera
|
|
|
174
174
|
Logger::SEVERITY_LABEL[@logger.level].downcase
|
|
175
175
|
end
|
|
176
176
|
|
|
177
|
-
# Change underlying logger, but keep log level
|
|
177
|
+
# Change underlying logger, but keep log level (default: INFO)
|
|
178
178
|
def logger_type=(new_log_type)
|
|
179
|
-
|
|
180
|
-
current_severity_integer = ENV
|
|
181
|
-
current_severity_integer = Logger::Severity::WARN if current_severity_integer.nil?
|
|
179
|
+
# [Integer]
|
|
180
|
+
current_severity_integer = @logger&.level || ENV['AS_LOG_LEVEL']&.to_i || Logger::Severity::INFO
|
|
182
181
|
case new_log_type
|
|
183
182
|
when :stderr
|
|
184
183
|
@logger = Logger.new($stderr, progname: @program_name, formatter: DEFAULT_FORMATTER)
|
data/lib/aspera/markdown.rb
CHANGED
|
@@ -26,6 +26,23 @@ module Aspera
|
|
|
26
26
|
def list(items)
|
|
27
27
|
items.map{ |i| "- #{i}"}.join("\n")
|
|
28
28
|
end
|
|
29
|
+
|
|
30
|
+
def heading(title, level: 1)
|
|
31
|
+
"#{'#' * level} #{title}\n\n"
|
|
32
|
+
end
|
|
33
|
+
|
|
34
|
+
# type: NOTE CAUTION WARNING IMPORTANT TIP INFO
|
|
35
|
+
def admonition(lines, type: 'INFO')
|
|
36
|
+
"> [!{type}]\n#{lines.map{ |l| "> #{l}"}.join("\n")}\n\n"
|
|
37
|
+
end
|
|
38
|
+
|
|
39
|
+
def code(lines, type: 'shell')
|
|
40
|
+
"```#{type}\n#{lines.join("\n")}\n```\n\n"
|
|
41
|
+
end
|
|
42
|
+
|
|
43
|
+
def paragraph(text)
|
|
44
|
+
"#{text}\n\n"
|
|
45
|
+
end
|
|
29
46
|
end
|
|
30
47
|
end
|
|
31
48
|
end
|
data/lib/aspera/oauth/base.rb
CHANGED
|
@@ -99,7 +99,7 @@ module Aspera
|
|
|
99
99
|
# lets try the existing refresh token
|
|
100
100
|
# NOTE: AoC admin token has no refresh, and lives by default 1800secs
|
|
101
101
|
if !refresh_token.nil?
|
|
102
|
-
Log.log.
|
|
102
|
+
Log.log.debug{"refresh token=[#{refresh_token}]"}
|
|
103
103
|
begin
|
|
104
104
|
http = create_token_call(base_params(add_secret: true).merge(grant_type: 'refresh_token', refresh_token: refresh_token))
|
|
105
105
|
# Save only if success
|
data/lib/aspera/oauth/web.rb
CHANGED
|
@@ -35,7 +35,7 @@ module Aspera
|
|
|
35
35
|
base_params.merge(response_type: 'code', redirect_uri: @redirect_uri, state: random_state)
|
|
36
36
|
)
|
|
37
37
|
# here, we need a human to authorize on a web page
|
|
38
|
-
Log.log.
|
|
38
|
+
Log.log.debug{"login_page_url=#{login_page_url}"}
|
|
39
39
|
# start a web server to receive request code
|
|
40
40
|
web_server = WebAuth.new(@redirect_uri, self.class.additional_info)
|
|
41
41
|
# start browser on login page
|
|
@@ -23,18 +23,18 @@ module Aspera
|
|
|
23
23
|
# one of CONVERSION_TYPES
|
|
24
24
|
attr_reader :conversion_type
|
|
25
25
|
|
|
26
|
-
#
|
|
27
|
-
#
|
|
28
|
-
#
|
|
26
|
+
# Node API MIME types are from: http://svn.apache.org/repos/asf/httpd/httpd/trunk/docs/conf/mime.types
|
|
27
|
+
# The resulting preview file type is taken from destination file extension.
|
|
28
|
+
# Conversion methods are provided by private methods: convert_<conversion_type>_to_<preview_format>
|
|
29
29
|
# -> conversion_type is one of FileTypes::CONVERSION_TYPES
|
|
30
30
|
# -> preview_format is one of Generator::PREVIEW_FORMATS
|
|
31
|
-
#
|
|
31
|
+
# The conversion video->mp4 is implemented in methods: convert_video_to_mp4_using_<video_conversion>
|
|
32
32
|
# -> conversion method is one of Generator::VIDEO_CONVERSION_METHODS
|
|
33
33
|
# @param src [String] source file path
|
|
34
34
|
# @param dst [String] destination file path
|
|
35
35
|
# @param options [Options] All conversion options
|
|
36
36
|
# @param main_temp_dir [String] Main temp folder, sub folder will be created for generation
|
|
37
|
-
# @param api_mime_type [String,nil] Optional
|
|
37
|
+
# @param api_mime_type [String,nil] Optional MIME type as provided by node api (or nil)
|
|
38
38
|
def initialize(src, dst, options, main_temp_dir, api_mime_type)
|
|
39
39
|
@source_file_path = src
|
|
40
40
|
@destination_file_path = dst
|
|
@@ -57,9 +57,9 @@ module Aspera
|
|
|
57
57
|
Aspera.assert(respond_to?(@processing_method, true)){"no processing known for #{conversion_type} -> #{@preview_format_sym}"}
|
|
58
58
|
end
|
|
59
59
|
|
|
60
|
-
#
|
|
60
|
+
# Create preview as specified in constructor.
|
|
61
61
|
def generate
|
|
62
|
-
Log.log.
|
|
62
|
+
Log.log.debug{"#{@source_file_path}->#{@destination_file_path} (#{@processing_method})"}
|
|
63
63
|
begin
|
|
64
64
|
send(@processing_method)
|
|
65
65
|
# check that generated size does not exceed maximum
|
|
@@ -76,17 +76,17 @@ module Aspera
|
|
|
76
76
|
|
|
77
77
|
private
|
|
78
78
|
|
|
79
|
-
#
|
|
79
|
+
# Creates a unique temp folder for file.
|
|
80
80
|
def this_tmpdir
|
|
81
81
|
FileUtils.mkdir_p(@temp_folder)
|
|
82
82
|
return @temp_folder
|
|
83
83
|
end
|
|
84
84
|
|
|
85
|
-
# @return offset in seconds suitable for ffmpeg -ss option
|
|
86
85
|
# @param duration of video
|
|
87
86
|
# @param start_offset of parts
|
|
88
87
|
# @param total_count of parts
|
|
89
88
|
# @param index of part (start at 1)
|
|
89
|
+
# @return [Integer] offset in seconds suitable for ffmpeg -ss option
|
|
90
90
|
def get_offset(duration, start_offset, total_count, index)
|
|
91
91
|
Aspera.assert_type(duration, Float){'duration'}
|
|
92
92
|
return start_offset + ((index - 1) * (duration - start_offset) / total_count)
|
|
@@ -3,15 +3,23 @@
|
|
|
3
3
|
module Aspera
|
|
4
4
|
# raised on error after REST call
|
|
5
5
|
class RestCallError < StandardError
|
|
6
|
-
|
|
6
|
+
def request
|
|
7
|
+
@context[:request]
|
|
8
|
+
end
|
|
9
|
+
|
|
10
|
+
def response
|
|
11
|
+
@context[:response]
|
|
12
|
+
end
|
|
13
|
+
|
|
14
|
+
def data
|
|
15
|
+
@context[:data]
|
|
16
|
+
end
|
|
7
17
|
|
|
8
|
-
# @param
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
@
|
|
13
|
-
@response = resp
|
|
14
|
-
super(msg)
|
|
18
|
+
# @param context [Hash,String] with keys :messages, :request, :response, :data
|
|
19
|
+
def initialize(context)
|
|
20
|
+
context = {messages: [context]} if context.is_a?(String)
|
|
21
|
+
@context = context
|
|
22
|
+
super(@context[:messages].join("\n"))
|
|
15
23
|
end
|
|
16
24
|
end
|
|
17
25
|
end
|
|
@@ -46,7 +46,7 @@ module Aspera
|
|
|
46
46
|
Log.log.error{"ERROR in handler:\n#{e.message}\n#{e.backtrace}"}
|
|
47
47
|
end
|
|
48
48
|
end
|
|
49
|
-
raise RestCallError.new(call_context
|
|
49
|
+
raise RestCallError.new(call_context) unless call_context[:messages].empty?
|
|
50
50
|
end
|
|
51
51
|
|
|
52
52
|
# add a new error handler (done at application initialization)
|
|
@@ -41,14 +41,14 @@ module Aspera
|
|
|
41
41
|
Log.log.debug{"retries=#{remaining_resumes}"}
|
|
42
42
|
# try to send the file until ascp is successful
|
|
43
43
|
loop do
|
|
44
|
-
Log.log.debug('
|
|
44
|
+
Log.log.debug('Starting task execution')
|
|
45
45
|
begin
|
|
46
46
|
# Call provided block: execute transfer
|
|
47
47
|
yield
|
|
48
48
|
# Exit retry loop if success
|
|
49
49
|
break
|
|
50
50
|
rescue Error => e
|
|
51
|
-
Log.log.warn{"
|
|
51
|
+
Log.log.warn{"An error occurred during task: #{e.message}"}
|
|
52
52
|
Log.log.debug{"Retryable ? #{e.retryable?}"}
|
|
53
53
|
# do not retry non-retryable
|
|
54
54
|
raise unless e.retryable?
|
data/lib/aspera/yaml.rb
ADDED
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require 'yaml'
|
|
4
|
+
|
|
5
|
+
module Aspera
|
|
6
|
+
module Yaml
|
|
7
|
+
# @param node [Psych::Nodes::Node] YAML node
|
|
8
|
+
# @param parent_path [Array<String>] Path of parent keys
|
|
9
|
+
# @param duplicate_keys [Array<Hash>] Accumulated duplicate keys
|
|
10
|
+
# @return [Array<String>] List of duplicate keys with their paths and occurrences
|
|
11
|
+
def find_duplicate_keys(node, parent_path = nil, duplicate_keys = nil)
|
|
12
|
+
duplicate_keys ||= []
|
|
13
|
+
parent_path ||= []
|
|
14
|
+
return duplicate_keys unless node.respond_to?(:children)
|
|
15
|
+
if node.is_a?(Psych::Nodes::Mapping)
|
|
16
|
+
counts = Hash.new(0)
|
|
17
|
+
key_nodes = Hash.new{ |h, k| h[k] = []}
|
|
18
|
+
node.children.each_slice(2) do |key_node, value_node|
|
|
19
|
+
if key_node&.value
|
|
20
|
+
counts[key_node.value] += 1
|
|
21
|
+
key_nodes[key_node.value] << key_node
|
|
22
|
+
find_duplicate_keys(value_node, parent_path + [key_node.value], duplicate_keys)
|
|
23
|
+
end
|
|
24
|
+
end
|
|
25
|
+
counts.each do |key_str, count|
|
|
26
|
+
next if count <= 1
|
|
27
|
+
path = (parent_path + [key_str]).join('.')
|
|
28
|
+
occurrences = key_nodes[key_str].map{ |kn| kn.start_line ? kn.start_line + 1 : 'unknown'}.map(&:to_s).join(', ')
|
|
29
|
+
duplicate_keys << "#{path}: #{occurrences}"
|
|
30
|
+
end
|
|
31
|
+
else
|
|
32
|
+
node.children.to_a.each{ |child| find_duplicate_keys(child, parent_path, duplicate_keys)}
|
|
33
|
+
end
|
|
34
|
+
duplicate_keys
|
|
35
|
+
end
|
|
36
|
+
|
|
37
|
+
# Safely load YAML content, raising an error if duplicate keys are found
|
|
38
|
+
# @param yaml [String] YAML content
|
|
39
|
+
# @return [Object] Parsed YAML content
|
|
40
|
+
# @raise [RuntimeError] If duplicate keys are found
|
|
41
|
+
def safe_load(yaml)
|
|
42
|
+
duplicate_keys = find_duplicate_keys(Psych.parse_stream(yaml))
|
|
43
|
+
raise "Duplicate keys: #{duplicate_keys.join('; ')}" unless duplicate_keys.empty?
|
|
44
|
+
YAML.safe_load(yaml)
|
|
45
|
+
end
|
|
46
|
+
|
|
47
|
+
module_function :find_duplicate_keys, :safe_load
|
|
48
|
+
end
|
|
49
|
+
end
|
data.tar.gz.sig
CHANGED
|
Binary file
|
metadata
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: aspera-cli
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version: 4.25.
|
|
4
|
+
version: 4.25.2
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- Laurent Martin
|
|
@@ -108,6 +108,20 @@ dependencies:
|
|
|
108
108
|
- - "~>"
|
|
109
109
|
- !ruby/object:Gem::Version
|
|
110
110
|
version: '3.0'
|
|
111
|
+
- !ruby/object:Gem::Dependency
|
|
112
|
+
name: marcel
|
|
113
|
+
requirement: !ruby/object:Gem::Requirement
|
|
114
|
+
requirements:
|
|
115
|
+
- - "~>"
|
|
116
|
+
- !ruby/object:Gem::Version
|
|
117
|
+
version: '1.1'
|
|
118
|
+
type: :runtime
|
|
119
|
+
prerelease: false
|
|
120
|
+
version_requirements: !ruby/object:Gem::Requirement
|
|
121
|
+
requirements:
|
|
122
|
+
- - "~>"
|
|
123
|
+
- !ruby/object:Gem::Version
|
|
124
|
+
version: '1.1'
|
|
111
125
|
- !ruby/object:Gem::Dependency
|
|
112
126
|
name: mime-types
|
|
113
127
|
requirement: !ruby/object:Gem::Requirement
|
|
@@ -430,9 +444,9 @@ files:
|
|
|
430
444
|
- lib/aspera/uri_reader.rb
|
|
431
445
|
- lib/aspera/web_auth.rb
|
|
432
446
|
- lib/aspera/web_server_simple.rb
|
|
447
|
+
- lib/aspera/yaml.rb
|
|
433
448
|
- lib/transferd_pb.rb
|
|
434
449
|
- lib/transferd_services_pb.rb
|
|
435
|
-
- release_notes.md
|
|
436
450
|
homepage: https://github.com/IBM/aspera-cli
|
|
437
451
|
licenses:
|
|
438
452
|
- Apache-2.0
|
metadata.gz.sig
CHANGED
|
Binary file
|