aspera-cli 4.12.0 → 4.14.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 (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