aspera-cli 4.12.0 → 4.14.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/CHANGELOG.md +45 -5
  4. data/CONTRIBUTING.md +113 -22
  5. data/README.md +1289 -754
  6. data/bin/ascli +3 -3
  7. data/examples/dascli +1 -1
  8. data/examples/rubyc +24 -0
  9. data/lib/aspera/aoc.rb +63 -74
  10. data/lib/aspera/ascmd.rb +5 -3
  11. data/lib/aspera/cli/basic_auth_plugin.rb +6 -6
  12. data/lib/aspera/cli/extended_value.rb +24 -37
  13. data/lib/aspera/cli/formatter.rb +23 -25
  14. data/lib/aspera/cli/info.rb +2 -4
  15. data/lib/aspera/cli/main.rb +27 -27
  16. data/lib/aspera/cli/manager.rb +143 -120
  17. data/lib/aspera/cli/plugin.rb +88 -43
  18. data/lib/aspera/cli/plugins/alee.rb +2 -2
  19. data/lib/aspera/cli/plugins/aoc.rb +235 -104
  20. data/lib/aspera/cli/plugins/ats.rb +16 -18
  21. data/lib/aspera/cli/plugins/bss.rb +3 -3
  22. data/lib/aspera/cli/plugins/config.rb +190 -373
  23. data/lib/aspera/cli/plugins/console.rb +4 -6
  24. data/lib/aspera/cli/plugins/cos.rb +12 -13
  25. data/lib/aspera/cli/plugins/faspex.rb +21 -21
  26. data/lib/aspera/cli/plugins/faspex5.rb +399 -150
  27. data/lib/aspera/cli/plugins/node.rb +260 -174
  28. data/lib/aspera/cli/plugins/orchestrator.rb +15 -18
  29. data/lib/aspera/cli/plugins/preview.rb +40 -62
  30. data/lib/aspera/cli/plugins/server.rb +33 -16
  31. data/lib/aspera/cli/plugins/shares.rb +24 -33
  32. data/lib/aspera/cli/plugins/sync.rb +6 -6
  33. data/lib/aspera/cli/transfer_agent.rb +47 -30
  34. data/lib/aspera/cli/version.rb +2 -1
  35. data/lib/aspera/colors.rb +9 -7
  36. data/lib/aspera/command_line_builder.rb +2 -1
  37. data/lib/aspera/cos_node.rb +1 -1
  38. data/lib/aspera/data/6 +0 -0
  39. data/lib/aspera/environment.rb +7 -3
  40. data/lib/aspera/fasp/agent_connect.rb +6 -1
  41. data/lib/aspera/fasp/agent_direct.rb +17 -17
  42. data/lib/aspera/fasp/agent_httpgw.rb +138 -60
  43. data/lib/aspera/fasp/agent_node.rb +14 -4
  44. data/lib/aspera/fasp/agent_trsdk.rb +2 -0
  45. data/lib/aspera/fasp/error_info.rb +2 -0
  46. data/lib/aspera/fasp/installation.rb +19 -19
  47. data/lib/aspera/fasp/parameters.rb +29 -20
  48. data/lib/aspera/fasp/parameters.yaml +5 -2
  49. data/lib/aspera/fasp/resume_policy.rb +3 -3
  50. data/lib/aspera/fasp/transfer_spec.rb +8 -5
  51. data/lib/aspera/fasp/uri.rb +23 -21
  52. data/lib/aspera/faspex_gw.rb +1 -0
  53. data/lib/aspera/faspex_postproc.rb +3 -3
  54. data/lib/aspera/hash_ext.rb +12 -2
  55. data/lib/aspera/keychain/macos_security.rb +13 -13
  56. data/lib/aspera/log.rb +1 -0
  57. data/lib/aspera/node.rb +73 -84
  58. data/lib/aspera/oauth.rb +4 -3
  59. data/lib/aspera/persistency_action_once.rb +1 -1
  60. data/lib/aspera/preview/file_types.rb +8 -6
  61. data/lib/aspera/preview/generator.rb +23 -11
  62. data/lib/aspera/preview/options.rb +3 -2
  63. data/lib/aspera/preview/terminal.rb +80 -0
  64. data/lib/aspera/preview/utils.rb +11 -11
  65. data/lib/aspera/proxy_auto_config.js +2 -2
  66. data/lib/aspera/rest.rb +42 -4
  67. data/lib/aspera/rest_call_error.rb +3 -1
  68. data/lib/aspera/secret_hider.rb +10 -5
  69. data/lib/aspera/ssh.rb +1 -1
  70. data/lib/aspera/sync.rb +41 -33
  71. data/lib/aspera/web_server_simple.rb +22 -18
  72. data.tar.gz.sig +0 -0
  73. metadata +40 -48
  74. metadata.gz.sig +0 -0
  75. data/docs/test_env.conf +0 -179
  76. data/examples/aoc.rb +0 -30
  77. data/examples/faspex4.rb +0 -94
  78. data/examples/node.rb +0 -96
  79. data/examples/server.rb +0 -93
  80. data/lib/aspera/data/7 +0 -0
@@ -48,38 +48,55 @@ module Aspera
48
48
  @config = config
49
49
  # command line can override transfer spec
50
50
  @transfer_spec_cmdline = {'create_dir' => true}
51
+ @transfer_info = {}
51
52
  # the currently selected transfer agent
52
53
  @agent = nil
53
54
  @progress_listener = Listener::ProgressMulti.new
54
55
  # source/destination pair, like "paths" of transfer spec
55
56
  @transfer_paths = nil
56
- @opt_mgr.set_obj_attr(:ts, self, :option_transfer_spec)
57
- @opt_mgr.add_opt_simple(:ts, "Override transfer spec values (Hash, e.g. use @json: prefix), current=#{@opt_mgr.get_option(:ts)}")
58
- @opt_mgr.add_opt_simple(:to_folder, 'Destination folder for transferred files')
59
- @opt_mgr.add_opt_simple(:sources, "How list of transferred files is provided (#{FILE_LIST_OPTIONS.join(',')})")
60
- @opt_mgr.add_opt_list(:src_type, %i[list pair], 'Type of file list')
61
- @opt_mgr.add_opt_list(:transfer, TRANSFER_AGENTS, 'Type of transfer agent')
62
- @opt_mgr.add_opt_simple(:transfer_info, 'Parameters for transfer agent')
63
- @opt_mgr.add_opt_list(:progress, %i[none native multi], 'Type of progress bar')
64
- @opt_mgr.set_option(:transfer, :direct)
65
- @opt_mgr.set_option(:src_type, :list)
66
- @opt_mgr.set_option(:progress, :native) # use native ascp progress bar as it is more reliable
57
+ @opt_mgr.declare(:ts, 'Override transfer spec values', types: Hash, handler: {o: self, m: :option_transfer_spec})
58
+ @opt_mgr.declare(:to_folder, 'Destination folder for transferred files')
59
+ @opt_mgr.declare(:sources, "How list of transferred files is provided (#{FILE_LIST_OPTIONS.join(',')})")
60
+ @opt_mgr.declare(:src_type, 'Type of file list', values: %i[list pair], default: :list)
61
+ @opt_mgr.declare(:transfer, 'Type of transfer agent', values: TRANSFER_AGENTS, default: :direct)
62
+ @opt_mgr.declare(:transfer_info, 'Parameters for transfer agent', types: Hash, handler: {o: self, m: :option_transfer_info})
63
+ @opt_mgr.declare(:progress, 'Type of progress bar', values: %i[none native multi], default: :native)
67
64
  @opt_mgr.parse_options!
68
65
  end
69
66
 
70
67
  def option_transfer_spec; @transfer_spec_cmdline; end
71
68
 
72
69
  # multiple option are merged
73
- def option_transfer_spec=(value); @transfer_spec_cmdline.merge!(value); end
70
+ def option_transfer_spec=(value)
71
+ raise 'option ts shall be a Hash' unless value.is_a?(Hash)
72
+ @transfer_spec_cmdline.deep_merge!(value)
73
+ end
74
74
 
75
+ # add other transfer spec parameters
75
76
  def option_transfer_spec_deep_merge(ts); @transfer_spec_cmdline.deep_merge!(ts); end
76
77
 
78
+ # @return [Hash] transfer spec with updated values from command line, including removed values
79
+ def updated_ts(transfer_spec={})
80
+ transfer_spec.deep_merge!(@transfer_spec_cmdline)
81
+ # recursively remove values that are nil (user wants to delete)
82
+ transfer_spec.deep_do { |hash, key, value, _unused| hash.delete(key) if value.nil?}
83
+ return transfer_spec
84
+ end
85
+
86
+ def option_transfer_info; @transfer_info; end
87
+
88
+ # multiple option are merged
89
+ def option_transfer_info=(value)
90
+ raise 'option transfer_info shall be a Hash' unless value.is_a?(Hash)
91
+ @transfer_info.deep_merge!(value)
92
+ end
93
+
77
94
  def agent_instance=(instance)
78
95
  @agent = instance
79
96
  @agent.add_listener(Listener::Logger.new)
80
97
  # use local progress bar if asked so, or if native and non local ascp (because only local ascp has native progress bar)
81
- if @opt_mgr.get_option(:progress, is_type: :mandatory).eql?(:multi) ||
82
- (@opt_mgr.get_option(:progress, is_type: :mandatory).eql?(:native) && !instance.class.to_s.eql?('Aspera::Fasp::AgentDirect'))
98
+ if @opt_mgr.get_option(:progress, mandatory: true).eql?(:multi) ||
99
+ (@opt_mgr.get_option(:progress, mandatory: true).eql?(:native) && !instance.class.to_s.eql?('Aspera::Fasp::AgentDirect'))
83
100
  @agent.add_listener(@progress_listener)
84
101
  end
85
102
  end
@@ -87,24 +104,24 @@ module Aspera
87
104
  # analyze options and create new agent if not already created or set
88
105
  def set_agent_by_options
89
106
  return nil unless @agent.nil?
90
- agent_type = @opt_mgr.get_option(:transfer, is_type: :mandatory)
107
+ agent_type = @opt_mgr.get_option(:transfer, mandatory: true)
91
108
  # agent plugin is loaded on demand to avoid loading unnecessary dependencies
92
109
  require "aspera/fasp/agent_#{agent_type}"
93
110
  agent_options = @opt_mgr.get_option(:transfer_info)
94
111
  raise CliBadArgument, "the transfer agent configuration shall be Hash, not #{agent_options.class} (#{agent_options}), "\
95
- 'use either @json:<json> or @preset:<parameter set name>' unless [Hash, NilClass].include?(agent_options.class)
96
- # special case
97
- if agent_type.eql?(:node) && agent_options.nil?
112
+ 'e.g. use @json:<json>' unless agent_options.is_a?(Hash)
113
+ # special case: use default node
114
+ if agent_type.eql?(:node) && agent_options.empty?
98
115
  param_set_name = @config.get_plugin_default_config_name(:node)
99
- raise CliBadArgument, "No default node configured, Please specify --#{:transfer_info.to_s.tr('_', '-')}" if param_set_name.nil?
116
+ raise CliBadArgument, "No default node configured. Please specify #{Manager.option_name_to_line(:transfer_info)}" if param_set_name.nil?
100
117
  agent_options = @config.preset_by_name(param_set_name)
101
118
  end
102
- # special case
103
- if agent_type.eql?(:direct) && @opt_mgr.get_option(:progress, is_type: :mandatory).eql?(:native)
104
- agent_options = {} if agent_options.nil?
119
+ # special case: native progress bar
120
+ if agent_type.eql?(:direct) && @opt_mgr.get_option(:progress, mandatory: true).eql?(:native)
105
121
  agent_options[:quiet] = false
106
122
  end
107
- agent_options = agent_options.symbolize_keys if agent_options.is_a?(Hash)
123
+ # normalize after getting from user or default node
124
+ agent_options = agent_options.symbolize_keys
108
125
  # get agent instance
109
126
  new_agent = Kernel.const_get("Aspera::Fasp::Agent#{agent_type.capitalize}").new(agent_options)
110
127
  self.agent_instance = new_agent
@@ -129,6 +146,7 @@ module Aspera
129
146
  return dest_folder
130
147
  end
131
148
 
149
+ # @return [Array] list of source files
132
150
  def source_list
133
151
  return ts_source_paths.map do |i|
134
152
  i['source']
@@ -156,7 +174,7 @@ module Aspera
156
174
  when FILE_LIST_FROM_TRANSFER_SPEC
157
175
  Log.log.debug('assume list provided in transfer spec')
158
176
  special_case_direct_with_list =
159
- @opt_mgr.get_option(:transfer, is_type: :mandatory).eql?(:direct) &&
177
+ @opt_mgr.get_option(:transfer, mandatory: true).eql?(:direct) &&
160
178
  Fasp::Parameters.ts_has_ascp_file_list(@transfer_spec_cmdline, @opt_mgr.get_option(:transfer_info))
161
179
  raise CliBadArgument, 'transfer spec on command line must have sources' if @transfer_paths.nil? && !special_case_direct_with_list
162
180
  # here we assume check of sources is made in transfer agent
@@ -171,7 +189,7 @@ module Aspera
171
189
  if !@transfer_paths.nil?
172
190
  Log.log.warn('--sources overrides paths from --ts')
173
191
  end
174
- case @opt_mgr.get_option(:src_type, is_type: :mandatory)
192
+ case @opt_mgr.get_option(:src_type, mandatory: true)
175
193
  when :list
176
194
  # when providing a list, just specify source
177
195
  @transfer_paths = file_list.map{|i|{'source' => i}}
@@ -196,7 +214,7 @@ module Aspera
196
214
  # init default if required in any case
197
215
  @transfer_spec_cmdline['destination_root'] ||= destination_folder(transfer_spec['direction'])
198
216
  when Fasp::TransferSpec::DIRECTION_SEND
199
- if transfer_spec.dig('tags', 'aspera', 'node', 'access_key')
217
+ if transfer_spec.dig('tags', Fasp::TransferSpec::TAG_RESERVED, 'node', 'access_key')
200
218
  # gen4
201
219
  @transfer_spec_cmdline.delete('destination_root') if @transfer_spec_cmdline.key?('destination_root_id')
202
220
  elsif transfer_spec.key?('token')
@@ -211,14 +229,13 @@ module Aspera
211
229
  end
212
230
  # update command line paths, unless destination already has one
213
231
  @transfer_spec_cmdline['paths'] = transfer_spec['paths'] || ts_source_paths
214
- transfer_spec.merge!(@transfer_spec_cmdline)
215
- # remove values that are nil (user wants to delete)
216
- transfer_spec.delete_if { |_key, value| value.nil? }
232
+ # updated transfer spec with command line
233
+ updated_ts(transfer_spec)
217
234
  # create transfer agent
218
235
  set_agent_by_options
219
236
  Log.log.debug{"transfer agent is a #{@agent.class}"}
220
237
  @agent.start_transfer(transfer_spec, token_regenerator: rest_token)
221
- # list of : :success or error message
238
+ # list of: :success or "error message string"
222
239
  result = @agent.wait_for_transfers_completion
223
240
  @progress_listener.reset
224
241
  Fasp::AgentBase.validate_status_list(result)
@@ -3,6 +3,7 @@
3
3
  module Aspera
4
4
  module Cli
5
5
  # for beta add extension : .beta1
6
- VERSION = '4.12.0'
6
+ # for dev version add extension : .pre
7
+ VERSION = '4.14.0'
7
8
  end
8
9
  end
data/lib/aspera/colors.rb CHANGED
@@ -1,16 +1,18 @@
1
1
  # frozen_string_literal: true
2
2
 
3
+ # cspell:words
4
+
3
5
  # simple vt100 colors
4
6
  class String
5
7
  class << self
6
8
  private
7
9
 
8
- def vtcmd(code); "\e[#{code}m"; end
10
+ def vt_cmd(code); "\e[#{code}m"; end
9
11
  end
10
12
  # see https://en.wikipedia.org/wiki/ANSI_escape_code
11
13
  # symbol is the method name added to String
12
14
  # it adds control chars to set color (and reset at the end).
13
- VTSTYLES = {
15
+ VT_STYLES = {
14
16
  bold: 1,
15
17
  italic: 3,
16
18
  underline: 4,
@@ -33,17 +35,17 @@ class String
33
35
  bg_cyan: 46,
34
36
  bg_gray: 47
35
37
  }.freeze
36
- private_constant :VTSTYLES
37
- # defines methods to String, one per entry in VTSTYLES
38
- VTSTYLES.each do |name, code|
38
+ private_constant :VT_STYLES
39
+ # defines methods to String, one per entry in VT_STYLES
40
+ VT_STYLES.each do |name, code|
39
41
  if $stderr.tty?
40
- begin_seq = vtcmd(code)
42
+ begin_seq = vt_cmd(code)
41
43
  end_code = 0 # by default reset all
42
44
  if code <= 7 then code + 20
43
45
  elsif code <= 37 then 39
44
46
  elsif code <= 47 then 49
45
47
  end
46
- end_seq = vtcmd(end_code)
48
+ end_seq = vt_cmd(end_code)
47
49
  define_method(name){"#{begin_seq}#{self}#{end_seq}"}
48
50
  else
49
51
  define_method(name){self}
@@ -9,7 +9,7 @@ module Aspera
9
9
  # parameter with one of those tags is a command line option with --
10
10
  CLI_OPTION_TYPE_SWITCH = %i[opt_without_arg opt_with_arg].freeze
11
11
  CLI_OPTION_TYPES = %i[special ignore envvar].concat(CLI_OPTION_TYPE_SWITCH).freeze
12
- OPTIONS_KEYS = %i[desc accepted_types default enum agents required cli ts].freeze
12
+ OPTIONS_KEYS = %i[desc accepted_types default enum agents required cli ts deprecation].freeze
13
13
  CLI_KEYS = %i[type switch convert variable].freeze
14
14
 
15
15
  private_constant :CLI_OPTION_TYPE_SWITCH, :OPTIONS_KEYS, :CLI_KEYS
@@ -37,6 +37,7 @@ module Aspera
37
37
  # by default : optional
38
38
  options[:mandatory] ||= false
39
39
  options[:desc] ||= ''
40
+ options[:desc] = "DEPRECATED: #{options[:deprecation]}\n#{options[:desc]}" if options.key?(:deprecation)
40
41
  cli = options[:cli]
41
42
  unsupported_cli_keys = cli.keys - CLI_KEYS
42
43
  raise "Unsupported cli keys: #{unsupported_cli_keys}" unless unsupported_cli_keys.empty?
@@ -65,7 +65,7 @@ module Aspera
65
65
  type: :basic,
66
66
  username: ats_info['AccessKey']['Id'],
67
67
  password: ats_info['AccessKey']['Secret']}},
68
- add_tspec: {'tags'=>{'aspera'=>{'node'=>{'storage_credentials'=>@storage_credentials}}}})
68
+ add_tspec: {'tags'=>{Fasp::TransferSpec::TAG_RESERVED=>{'node'=>{'storage_credentials'=>@storage_credentials}}}})
69
69
  # update storage_credentials AND Rest params
70
70
  generate_token
71
71
  end
data/lib/aspera/data/6 CHANGED
Binary file
@@ -3,6 +3,8 @@
3
3
  require 'aspera/log'
4
4
  require 'rbconfig'
5
5
 
6
+ # cspell:words MEBI mswin bccwin
7
+
6
8
  module Aspera
7
9
  # detect OS, architecture, and specific stuff
8
10
  class Environment
@@ -84,12 +86,14 @@ module Aspera
84
86
  end
85
87
 
86
88
  # value is provided in block
87
- def write_file_restricted(path, force: false)
89
+ def write_file_restricted(path, force: false, mode: nil)
88
90
  raise 'coding error, missing content block' unless block_given?
89
91
  if force || !File.exist?(path)
90
- File.unlink(path) rescue nil # Windows may give error
92
+ # Windows may give error
93
+ File.unlink(path) rescue nil
94
+ # content provided by block
91
95
  File.write(path, yield)
92
- restrict_file_access(path)
96
+ restrict_file_access(path, mode: mode)
93
97
  end
94
98
  return path
95
99
  end
@@ -9,7 +9,9 @@ require 'tty-spinner'
9
9
  module Aspera
10
10
  module Fasp
11
11
  class AgentConnect < Aspera::Fasp::AgentBase
12
+ # try twice the main init url in sequence
12
13
  CONNECT_START_URIS = ['fasp://initialize', 'fasp://initialize', 'aspera-drive://initialize', 'https://test-connect.ibmaspera.com/']
14
+ # delay between each try to start connect
13
15
  SLEEP_SEC_BETWEEN_RETRY = 3
14
16
  private_constant :CONNECT_START_URIS, :SLEEP_SEC_BETWEEN_RETRY
15
17
  def initialize(_options)
@@ -66,7 +68,7 @@ module Aspera
66
68
  }]}
67
69
  # asynchronous anyway
68
70
  res = @connect_api.create('transfers/start', connect_transfer_args)[:data]
69
- @xfer_id = res['transfer_specs'].first['transfer_spec']['tags']['aspera']['xfer_id']
71
+ @xfer_id = res['transfer_specs'].first['transfer_spec']['tags'][Fasp::TransferSpec::TAG_RESERVED]['xfer_id']
70
72
  end
71
73
 
72
74
  def wait_for_transfers_completion
@@ -106,6 +108,9 @@ module Aspera
106
108
  when 'failed'
107
109
  spinner&.error
108
110
  raise Fasp::Error, transfer['error_desc']
111
+ when 'cancelled'
112
+ spinner&.error
113
+ raise Fasp::Error, 'Transfer cancelled by user'
109
114
  else
110
115
  raise Fasp::Error, "unknown status: #{transfer['status']}: #{transfer['error_desc']}"
111
116
  end
@@ -25,7 +25,7 @@ module Aspera
25
25
  multi_incr_udp: true,
26
26
  resume: {},
27
27
  ascp_args: [],
28
- quiet: true # by default no interactive progress bar
28
+ quiet: true # by default no native ascp progress bar
29
29
  }.freeze
30
30
  private_constant :DEFAULT_OPTIONS
31
31
 
@@ -37,15 +37,15 @@ module Aspera
37
37
  # clone transfer spec because we modify it (first level keys)
38
38
  transfer_spec = transfer_spec.clone
39
39
  # if there is aspera tags
40
- if transfer_spec['tags'].is_a?(Hash) && transfer_spec['tags']['aspera'].is_a?(Hash)
40
+ if transfer_spec['tags'].is_a?(Hash) && transfer_spec['tags'][Fasp::TransferSpec::TAG_RESERVED].is_a?(Hash)
41
41
  # TODO: what is this for ? only on local ascp ?
42
42
  # NOTE: important: transfer id must be unique: generate random id
43
43
  # using a non unique id results in discard of tags in AoC, and a package is never finalized
44
44
  # all sessions in a multi-session transfer must have the same xfer_id (see admin manual)
45
- transfer_spec['tags']['aspera']['xfer_id'] ||= SecureRandom.uuid
45
+ transfer_spec['tags'][Fasp::TransferSpec::TAG_RESERVED]['xfer_id'] ||= SecureRandom.uuid
46
46
  Log.log.debug{"xfer id=#{transfer_spec['xfer_id']}"}
47
47
  # TODO: useful ? node only ?
48
- transfer_spec['tags']['aspera']['xfer_retry'] ||= 3600
48
+ transfer_spec['tags'][Fasp::TransferSpec::TAG_RESERVED]['xfer_retry'] ||= 3600
49
49
  end
50
50
  Log.dump('ts', transfer_spec)
51
51
 
@@ -82,12 +82,12 @@ module Aspera
82
82
  end
83
83
 
84
84
  # compute known args
85
- env_args = Parameters.ts_to_env_args(transfer_spec, wss: @options[:wss], ascp_args: @options[:ascp_args])
85
+ env_args = Parameters.new(transfer_spec, @options).ascp_args
86
86
 
87
87
  # add fallback cert and key as arguments if needed
88
- if %w[1 force].include?(transfer_spec['http_fallback'])
89
- env_args[:args].unshift('-Y', Installation.instance.path(:fallback_key))
90
- env_args[:args].unshift('-I', Installation.instance.path(:fallback_cert))
88
+ if ['1', 1, true, 'force'].include?(transfer_spec['http_fallback'])
89
+ env_args[:args].unshift('-Y', Installation.instance.path(:fallback_cert_privkey))
90
+ env_args[:args].unshift('-I', Installation.instance.path(:fallback_certificate))
91
91
  end
92
92
 
93
93
  env_args[:args].unshift('-q') if @options[:quiet]
@@ -183,20 +183,20 @@ module Aspera
183
183
  end
184
184
  # (optional) check it exists
185
185
  raise Fasp::Error, "no such file: #{ascp_path}" unless File.exist?(ascp_path)
186
- # open random local TCP port for listening for ascp management
186
+ # open an available (0) local TCP port as ascp management
187
187
  mgt_sock = TCPServer.new('127.0.0.1', 0)
188
188
  # clone arguments as we eed to modify with mgt port
189
189
  ascp_arguments = env_args[:args].clone
190
- # add management port
190
+ # add management port on the selected local port
191
191
  ascp_arguments.unshift('-M', mgt_sock.addr[1].to_s)
192
192
  # start ascp in sub process
193
193
  Log.log.debug do
194
- 'execute: ' +
195
- env_args[:env].map{|k, v| "#{k}=#{Shellwords.shellescape(v)}"}.join(' ') +
196
- ' ' +
197
- Shellwords.shellescape(ascp_path) +
198
- ' ' +
199
- ascp_arguments.map{|a|Shellwords.shellescape(a)}.join(' ')
194
+ [
195
+ 'execute:',
196
+ env_args[:env].map{|k, v| "#{k}=#{Shellwords.shellescape(v)}"},
197
+ Shellwords.shellescape(ascp_path),
198
+ ascp_arguments.map{|a|Shellwords.shellescape(a)}
199
+ ].flatten.join(' ')
200
200
  end
201
201
  # start process
202
202
  ascp_pid = Process.spawn(env_args[:env], [ascp_path, ascp_path], *ascp_arguments)
@@ -334,7 +334,7 @@ module Aspera
334
334
  # @param options : keys(symbol): see DEFAULT_OPTIONS
335
335
  def initialize(options=nil)
336
336
  super()
337
- # all transfer jobs, key = SecureRandom.uuid, protected by mutex, condvar on change
337
+ # all transfer jobs, key = SecureRandom.uuid, protected by mutex, cond var on change
338
338
  @jobs = {}
339
339
  # mutex protects global data accessed by threads
340
340
  @mutex = Mutex.new