aspera-cli 4.18.1 → 4.19.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.
- checksums.yaml +4 -4
 - checksums.yaml.gz.sig +0 -0
 - data/CHANGELOG.md +13 -0
 - data/CONTRIBUTING.md +5 -12
 - data/README.md +60 -29
 - data/examples/build_exec +85 -0
 - data/lib/aspera/agent/base.rb +2 -0
 - data/lib/aspera/agent/direct.rb +108 -104
 - data/lib/aspera/api/aoc.rb +2 -2
 - data/lib/aspera/api/httpgw.rb +91 -56
 - data/lib/aspera/ascp/installation.rb +47 -32
 - data/lib/aspera/ascp/management.rb +4 -1
 - data/lib/aspera/ascp/products.rb +1 -7
 - data/lib/aspera/cli/formatter.rb +24 -18
 - data/lib/aspera/cli/manager.rb +10 -10
 - data/lib/aspera/cli/plugin.rb +2 -2
 - data/lib/aspera/cli/plugin_factory.rb +10 -1
 - data/lib/aspera/cli/plugins/config.rb +15 -10
 - data/lib/aspera/cli/plugins/node.rb +4 -3
 - data/lib/aspera/cli/plugins/server.rb +1 -1
 - data/lib/aspera/cli/plugins/shares.rb +11 -7
 - data/lib/aspera/cli/sync_actions.rb +72 -31
 - data/lib/aspera/cli/transfer_agent.rb +1 -0
 - data/lib/aspera/cli/transfer_progress.rb +1 -1
 - data/lib/aspera/cli/version.rb +1 -1
 - data/lib/aspera/environment.rb +43 -10
 - data/lib/aspera/faspex_gw.rb +1 -1
 - data/lib/aspera/keychain/encrypted_hash.rb +2 -0
 - data/lib/aspera/log.rb +1 -0
 - data/lib/aspera/node_simulator.rb +1 -1
 - data/lib/aspera/oauth/jwt.rb +1 -1
 - data/lib/aspera/oauth/url_json.rb +2 -0
 - data/lib/aspera/oauth/web.rb +5 -4
 - data/lib/aspera/secret_hider.rb +3 -2
 - data/lib/aspera/ssh.rb +1 -1
 - data/lib/aspera/transfer/faux_file.rb +7 -5
 - data/lib/aspera/transfer/parameters.rb +27 -19
 - data/lib/aspera/transfer/spec.rb +8 -10
 - data/lib/aspera/transfer/sync.rb +52 -47
 - data/lib/aspera/web_auth.rb +0 -1
 - data/lib/aspera/web_server_simple.rb +24 -13
 - data.tar.gz.sig +0 -0
 - metadata +3 -3
 - metadata.gz.sig +0 -0
 - data/examples/rubyc +0 -24
 
| 
         @@ -41,8 +41,11 @@ module Aspera 
     | 
|
| 
       41 
41 
     | 
    
         
             
                    </CONF>
         
     | 
| 
       42 
42 
     | 
    
         
             
                  END_OF_CONFIG_FILE
         
     | 
| 
       43 
43 
     | 
    
         
             
                  # all ascp files (in SDK)
         
     | 
| 
       44 
     | 
    
         
            -
                   
     | 
| 
      
 44 
     | 
    
         
            +
                  EXE_FILES = %i[ascp ascp4 async].freeze
         
     | 
| 
      
 45 
     | 
    
         
            +
                  FILES = %i[transferd ssh_private_dsa ssh_private_rsa aspera_license aspera_conf fallback_certificate fallback_private_key].unshift(*EXE_FILES).freeze
         
     | 
| 
       45 
46 
     | 
    
         
             
                  private_constant :EXT_RUBY_PROTOBUF, :RB_SDK_FOLDER, :DEFAULT_ASPERA_CONF, :FILES
         
     | 
| 
      
 47 
     | 
    
         
            +
                  # options for SSH client private key
         
     | 
| 
      
 48 
     | 
    
         
            +
                  CLIENT_SSH_KEY_OPTIONS = %i{dsa_rsa rsa per_client}.freeze
         
     | 
| 
       46 
49 
     | 
    
         
             
                  # set ascp executable path
         
     | 
| 
       47 
50 
     | 
    
         
             
                  def ascp_path=(v)
         
     | 
| 
       48 
51 
     | 
    
         
             
                    @path_to_ascp = v
         
     | 
| 
         @@ -110,14 +113,14 @@ module Aspera 
     | 
|
| 
       110 
113 
     | 
    
         
             
                  def path(k)
         
     | 
| 
       111 
114 
     | 
    
         
             
                    file_is_optional = false
         
     | 
| 
       112 
115 
     | 
    
         
             
                    case k
         
     | 
| 
       113 
     | 
    
         
            -
                    when  
     | 
| 
      
 116 
     | 
    
         
            +
                    when *EXE_FILES
         
     | 
| 
      
 117 
     | 
    
         
            +
                      file_is_optional = k.eql?(:async)
         
     | 
| 
       114 
118 
     | 
    
         
             
                      use_ascp_from_product(FIRST_FOUND) if @path_to_ascp.nil?
         
     | 
| 
       115 
     | 
    
         
            -
                      file = @path_to_ascp
         
     | 
| 
       116 
119 
     | 
    
         
             
                      # NOTE: that there might be a .exe at the end
         
     | 
| 
       117 
     | 
    
         
            -
                      file =  
     | 
| 
      
 120 
     | 
    
         
            +
                      file = @path_to_ascp.gsub('ascp', k.to_s)
         
     | 
| 
       118 
121 
     | 
    
         
             
                    when :transferd
         
     | 
| 
       119 
     | 
    
         
            -
                      file = transferd_filepath
         
     | 
| 
       120 
122 
     | 
    
         
             
                      file_is_optional = true
         
     | 
| 
      
 123 
     | 
    
         
            +
                      file = transferd_filepath
         
     | 
| 
       121 
124 
     | 
    
         
             
                    when :ssh_private_dsa, :ssh_private_rsa
         
     | 
| 
       122 
125 
     | 
    
         
             
                      # assume last 3 letters are type
         
     | 
| 
       123 
126 
     | 
    
         
             
                      type = k.to_s[-3..-1].to_sym
         
     | 
| 
         @@ -151,8 +154,16 @@ module Aspera 
     | 
|
| 
       151 
154 
     | 
    
         
             
                    return DataRepository.instance.item(:uuid)
         
     | 
| 
       152 
155 
     | 
    
         
             
                  end
         
     | 
| 
       153 
156 
     | 
    
         | 
| 
       154 
     | 
    
         
            -
                   
     | 
| 
       155 
     | 
    
         
            -
             
     | 
| 
      
 157 
     | 
    
         
            +
                  # get paths of SSH keys to use for ascp client
         
     | 
| 
      
 158 
     | 
    
         
            +
                  # @param types [Symbol] types to use
         
     | 
| 
      
 159 
     | 
    
         
            +
                  def aspera_token_ssh_key_paths(types)
         
     | 
| 
      
 160 
     | 
    
         
            +
                    Aspera.assert_values(types, CLIENT_SSH_KEY_OPTIONS)
         
     | 
| 
      
 161 
     | 
    
         
            +
                    return case types
         
     | 
| 
      
 162 
     | 
    
         
            +
                           when :dsa_rsa, :rsa
         
     | 
| 
      
 163 
     | 
    
         
            +
                             types.to_s.split('_').map{|i|Installation.instance.path("ssh_private_#{i}".to_sym)}
         
     | 
| 
      
 164 
     | 
    
         
            +
                           when :per_client
         
     | 
| 
      
 165 
     | 
    
         
            +
                             raise 'Not yet implemented'
         
     | 
| 
      
 166 
     | 
    
         
            +
                           end
         
     | 
| 
       156 
167 
     | 
    
         
             
                  end
         
     | 
| 
       157 
168 
     | 
    
         | 
| 
       158 
169 
     | 
    
         
             
                  # use in plugin `config`
         
     | 
| 
         @@ -169,13 +180,14 @@ module Aspera 
     | 
|
| 
       169 
180 
     | 
    
         
             
                    raise "An error occurred when testing #{ascp_filename}: #{cmd_out}" unless $CHILD_STATUS == 0
         
     | 
| 
       170 
181 
     | 
    
         
             
                    # get version from ascp, only after full extract, as windows requires DLLs (SSL/TLS/etc...)
         
     | 
| 
       171 
182 
     | 
    
         
             
                    m = cmd_out.match(/ version ([0-9.]+)/)
         
     | 
| 
       172 
     | 
    
         
            -
                    exe_version = m[1] unless m.nil?
         
     | 
| 
      
 183 
     | 
    
         
            +
                    exe_version = m[1].gsub(/\.$/, '') unless m.nil?
         
     | 
| 
       173 
184 
     | 
    
         
             
                    return exe_version
         
     | 
| 
       174 
185 
     | 
    
         
             
                  end
         
     | 
| 
       175 
186 
     | 
    
         | 
| 
       176 
     | 
    
         
            -
                  def  
     | 
| 
      
 187 
     | 
    
         
            +
                  def ascp_pvcl_info
         
     | 
| 
      
 188 
     | 
    
         
            +
                    data = {}
         
     | 
| 
       177 
189 
     | 
    
         
             
                    # read PATHs from ascp directly, and pvcl modules as well
         
     | 
| 
       178 
     | 
    
         
            -
                    Open3.popen3( 
     | 
| 
      
 190 
     | 
    
         
            +
                    Open3.popen3(ascp_path, '-DDL-') do |_stdin, _stdout, stderr, thread|
         
     | 
| 
       179 
191 
     | 
    
         
             
                      last_line = ''
         
     | 
| 
       180 
192 
     | 
    
         
             
                      while (line = stderr.gets)
         
     | 
| 
       181 
193 
     | 
    
         
             
                        line.chomp!
         
     | 
| 
         @@ -194,32 +206,32 @@ module Aspera 
     | 
|
| 
       194 
206 
     | 
    
         
             
                          data['product_name'] = Regexp.last_match(1)
         
     | 
| 
       195 
207 
     | 
    
         
             
                          data['product_version'] = Regexp.last_match(2)
         
     | 
| 
       196 
208 
     | 
    
         
             
                        when /^LOG Initializing FASP version ([^,]+),/
         
     | 
| 
       197 
     | 
    
         
            -
                          data[' 
     | 
| 
      
 209 
     | 
    
         
            +
                          data['sdk_ascp_version'] = Regexp.last_match(1)
         
     | 
| 
       198 
210 
     | 
    
         
             
                        end
         
     | 
| 
       199 
211 
     | 
    
         
             
                      end
         
     | 
| 
       200 
212 
     | 
    
         
             
                      if !thread.value.exitstatus.eql?(1) && !data.key?('root')
         
     | 
| 
       201 
213 
     | 
    
         
             
                        raise last_line
         
     | 
| 
       202 
214 
     | 
    
         
             
                      end
         
     | 
| 
       203 
215 
     | 
    
         
             
                    end
         
     | 
| 
      
 216 
     | 
    
         
            +
                    return data
         
     | 
| 
       204 
217 
     | 
    
         
             
                  end
         
     | 
| 
       205 
218 
     | 
    
         | 
| 
       206 
219 
     | 
    
         
             
                  # extract some stings from ascp binary
         
     | 
| 
       207 
     | 
    
         
            -
                  def  
     | 
| 
       208 
     | 
    
         
            -
                     
     | 
| 
       209 
     | 
    
         
            -
                    File.binread( 
     | 
| 
      
 220 
     | 
    
         
            +
                  def ascp_ssl_info
         
     | 
| 
      
 221 
     | 
    
         
            +
                    data = {}
         
     | 
| 
      
 222 
     | 
    
         
            +
                    File.binread(ascp_path).scan(/[\x20-\x7E]{10,}/) do |bin_string|
         
     | 
| 
       210 
223 
     | 
    
         
             
                      if (m = bin_string.match(/OPENSSLDIR.*"(.*)"/))
         
     | 
| 
       211 
224 
     | 
    
         
             
                        data['openssldir'] = m[1]
         
     | 
| 
       212 
225 
     | 
    
         
             
                      elsif (m = bin_string.match(/OpenSSL (\d[^ -]+)/))
         
     | 
| 
       213 
226 
     | 
    
         
             
                        data['openssl_version'] = m[1]
         
     | 
| 
       214 
227 
     | 
    
         
             
                      end
         
     | 
| 
       215 
     | 
    
         
            -
                    end if File.file?( 
     | 
| 
      
 228 
     | 
    
         
            +
                    end if File.file?(ascp_path)
         
     | 
| 
      
 229 
     | 
    
         
            +
                    return data
         
     | 
| 
       216 
230 
     | 
    
         
             
                  end
         
     | 
| 
       217 
231 
     | 
    
         | 
| 
       218 
232 
     | 
    
         
             
                  def ascp_info
         
     | 
| 
       219 
     | 
    
         
            -
                     
     | 
| 
       220 
     | 
    
         
            -
                     
     | 
| 
       221 
     | 
    
         
            -
                    ascp_add_openssl(data)
         
     | 
| 
       222 
     | 
    
         
            -
                    return data
         
     | 
| 
      
 233 
     | 
    
         
            +
                    files = file_paths
         
     | 
| 
      
 234 
     | 
    
         
            +
                    return files.merge(ascp_pvcl_info).merge(ascp_ssl_info)
         
     | 
| 
       223 
235 
     | 
    
         
             
                  end
         
     | 
| 
       224 
236 
     | 
    
         | 
| 
       225 
237 
     | 
    
         
             
                  # download aspera SDK or use local file
         
     | 
| 
         @@ -263,19 +275,22 @@ module Aspera 
     | 
|
| 
       263 
275 
     | 
    
         
             
                    # ensure license file are generated so that ascp invocation for version works
         
     | 
| 
       264 
276 
     | 
    
         
             
                    path(:aspera_license)
         
     | 
| 
       265 
277 
     | 
    
         
             
                    path(:aspera_conf)
         
     | 
| 
       266 
     | 
    
         
            -
                     
     | 
| 
       267 
     | 
    
         
            -
                     
     | 
| 
       268 
     | 
    
         
            -
                    raise "No #{ 
     | 
| 
       269 
     | 
    
         
            -
                     
     | 
| 
       270 
     | 
    
         
            -
             
     | 
| 
       271 
     | 
    
         
            -
             
     | 
| 
       272 
     | 
    
         
            -
                     
     | 
| 
       273 
     | 
    
         
            -
                     
     | 
| 
       274 
     | 
    
         
            -
                     
     | 
| 
       275 
     | 
    
         
            -
                     
     | 
| 
       276 
     | 
    
         
            -
                     
     | 
| 
       277 
     | 
    
         
            -
                     
     | 
| 
       278 
     | 
    
         
            -
                     
     | 
| 
      
 278 
     | 
    
         
            +
                    sdk_ascp_file = Products.ascp_filename
         
     | 
| 
      
 279 
     | 
    
         
            +
                    sdk_ascp_path = File.join(sdk_folder, sdk_ascp_file)
         
     | 
| 
      
 280 
     | 
    
         
            +
                    raise "No #{sdk_ascp_file} found in SDK archive" unless File.exist?(sdk_ascp_path)
         
     | 
| 
      
 281 
     | 
    
         
            +
                    EXE_FILES.each do |exe_sym|
         
     | 
| 
      
 282 
     | 
    
         
            +
                      exe_path = sdk_ascp_path.gsub('ascp', exe_sym.to_s)
         
     | 
| 
      
 283 
     | 
    
         
            +
                      Environment.restrict_file_access(exe_path, mode: 0o755) if File.exist?(exe_path)
         
     | 
| 
      
 284 
     | 
    
         
            +
                    end
         
     | 
| 
      
 285 
     | 
    
         
            +
                    sdk_ascp_version = get_ascp_version(sdk_ascp_path)
         
     | 
| 
      
 286 
     | 
    
         
            +
                    sdk_daemon_path = transferd_filepath
         
     | 
| 
      
 287 
     | 
    
         
            +
                    Log.log.warn{"No #{sdk_daemon_path} in SDK archive"} unless File.exist?(sdk_daemon_path)
         
     | 
| 
      
 288 
     | 
    
         
            +
                    Environment.restrict_file_access(sdk_daemon_path, mode: 0o755) if File.exist?(sdk_daemon_path)
         
     | 
| 
      
 289 
     | 
    
         
            +
                    transferd_version = get_exe_version(sdk_daemon_path, 'version')
         
     | 
| 
      
 290 
     | 
    
         
            +
                    sdk_name = 'IBM Aspera Transfer SDK'
         
     | 
| 
      
 291 
     | 
    
         
            +
                    sdk_version = transferd_version || sdk_ascp_version
         
     | 
| 
      
 292 
     | 
    
         
            +
                    File.write(File.join(sdk_folder, Products::INFO_META_FILE), "<product><name>#{sdk_name}</name><version>#{sdk_version}</version></product>")
         
     | 
| 
      
 293 
     | 
    
         
            +
                    return sdk_name, sdk_version
         
     | 
| 
       279 
294 
     | 
    
         
             
                  end
         
     | 
| 
       280 
295 
     | 
    
         | 
| 
       281 
296 
     | 
    
         
             
                  private
         
     | 
| 
         @@ -188,7 +188,7 @@ module Aspera 
     | 
|
| 
       188 
188 
     | 
    
         
             
                  # empty line is separator to end event information
         
     | 
| 
       189 
189 
     | 
    
         
             
                  MGT_FRAME_SEPARATOR = ''
         
     | 
| 
       190 
190 
     | 
    
         
             
                  # fields description for JSON generation
         
     | 
| 
       191 
     | 
    
         
            -
                  #  
     | 
| 
      
 191 
     | 
    
         
            +
                  # cspell: disable
         
     | 
| 
       192 
192 
     | 
    
         
             
                  INTEGER_FIELDS = %w[Bytescont FaspFileArgIndex StartByte Rate MinRate Port Priority RateCap MinRateCap TCPPort CreatePolicy TimePolicy
         
     | 
| 
       193 
193 
     | 
    
         
             
                                      DatagramSize XoptFlags VLinkVersion PeerVLinkVersion DSPipelineDepth PeerDSPipelineDepth ReadBlockSize WriteBlockSize
         
     | 
| 
       194 
194 
     | 
    
         
             
                                      ClusterNumNodes ClusterNodeId Size Written Loss FileBytes PreTransferBytes TransferBytes PMTU Elapsedusec ArgScansAttempted
         
     | 
| 
         @@ -219,6 +219,9 @@ module Aspera 
     | 
|
| 
       219 
219 
     | 
    
         
             
                  end
         
     | 
| 
       220 
220 
     | 
    
         
             
                  attr_reader :last_event
         
     | 
| 
       221 
221 
     | 
    
         | 
| 
      
 222 
     | 
    
         
            +
                  # process line of mgt port event
         
     | 
| 
      
 223 
     | 
    
         
            +
                  # @param line [String] line of mgt port event
         
     | 
| 
      
 224 
     | 
    
         
            +
                  # @return [Hash] event hash or nil if event is not yet complete
         
     | 
| 
       222 
225 
     | 
    
         
             
                  def process_line(line)
         
     | 
| 
       223 
226 
     | 
    
         
             
                    # Log.log.debug{"line=[#{line}]"}
         
     | 
| 
       224 
227 
     | 
    
         
             
                    case line
         
     | 
    
        data/lib/aspera/ascp/products.rb
    CHANGED
    
    | 
         @@ -126,7 +126,7 @@ module Aspera 
     | 
|
| 
       126 
126 
     | 
    
         | 
| 
       127 
127 
     | 
    
         
             
                    # filename for ascp with optional extension (Windows)
         
     | 
| 
       128 
128 
     | 
    
         
             
                    def ascp_filename
         
     | 
| 
       129 
     | 
    
         
            -
                      return  
     | 
| 
      
 129 
     | 
    
         
            +
                      return "ascp#{Environment.exe_extension}"
         
     | 
| 
       130 
130 
     | 
    
         
             
                    end
         
     | 
| 
       131 
131 
     | 
    
         | 
| 
       132 
132 
     | 
    
         
             
                    # @return folder paths for specified applications
         
     | 
| 
         @@ -150,12 +150,6 @@ module Aspera 
     | 
|
| 
       150 
150 
     | 
    
         
             
                      end
         
     | 
| 
       151 
151 
     | 
    
         
             
                      raise "no connect uri file found in #{folder}"
         
     | 
| 
       152 
152 
     | 
    
         
             
                    end
         
     | 
| 
       153 
     | 
    
         
            -
             
     | 
| 
       154 
     | 
    
         
            -
                    # @ return path to configuration file of aspera CLI
         
     | 
| 
       155 
     | 
    
         
            -
                    # def cli_conf_file
         
     | 
| 
       156 
     | 
    
         
            -
                    #  connect = folders(PRODUCT_CLI_V1)
         
     | 
| 
       157 
     | 
    
         
            -
                    #  return File.join(connect[:app_root], BIN_SUBFOLDER, '.aspera_cli_conf')
         
     | 
| 
       158 
     | 
    
         
            -
                    # end
         
     | 
| 
       159 
153 
     | 
    
         
             
                  end
         
     | 
| 
       160 
154 
     | 
    
         
             
                end
         
     | 
| 
       161 
155 
     | 
    
         
             
              end
         
     | 
    
        data/lib/aspera/cli/formatter.rb
    CHANGED
    
    | 
         @@ -98,11 +98,12 @@ module Aspera 
     | 
|
| 
       98 
98 
     | 
    
         
             
                  CSV_RECORD_SEPARATOR = "\n"
         
     | 
| 
       99 
99 
     | 
    
         
             
                  CSV_FIELD_SEPARATOR = ','
         
     | 
| 
       100 
100 
     | 
    
         
             
                  # supported output formats
         
     | 
| 
       101 
     | 
    
         
            -
                  DISPLAY_FORMATS = %i[text nagios ruby json jsonpp yaml table csv image].freeze
         
     | 
| 
      
 101 
     | 
    
         
            +
                  DISPLAY_FORMATS = %i[text nagios ruby json jsonpp yaml table multi csv image].freeze
         
     | 
| 
       102 
102 
     | 
    
         
             
                  # user output levels
         
     | 
| 
       103 
103 
     | 
    
         
             
                  DISPLAY_LEVELS = %i[info data error].freeze
         
     | 
| 
      
 104 
     | 
    
         
            +
                  FIELD_VALUE_HEADINGS = %i[key value].freeze
         
     | 
| 
       104 
105 
     | 
    
         | 
| 
       105 
     | 
    
         
            -
                  private_constant :DISPLAY_FORMATS, :DISPLAY_LEVELS, :CSV_RECORD_SEPARATOR, :CSV_FIELD_SEPARATOR
         
     | 
| 
      
 106 
     | 
    
         
            +
                  private_constant :DISPLAY_FORMATS, :DISPLAY_LEVELS, :CSV_RECORD_SEPARATOR, :CSV_FIELD_SEPARATOR, :FIELD_VALUE_HEADINGS
         
     | 
| 
       106 
107 
     | 
    
         
             
                  # prefix to display error messages in user messages (terminal)
         
     | 
| 
       107 
108 
     | 
    
         
             
                  ERROR_FLASH = 'ERROR:'.bg_red.gray.blink.freeze
         
     | 
| 
       108 
109 
     | 
    
         
             
                  WARNING_FLASH = 'WARNING:'.bg_brown.black.blink.freeze
         
     | 
| 
         @@ -116,7 +117,7 @@ module Aspera 
     | 
|
| 
       116 
117 
     | 
    
         | 
| 
       117 
118 
     | 
    
         
             
                    def tick(yes)
         
     | 
| 
       118 
119 
     | 
    
         
             
                      result =
         
     | 
| 
       119 
     | 
    
         
            -
                        if Environment.terminal_supports_unicode?
         
     | 
| 
      
 120 
     | 
    
         
            +
                        if Environment.instance.terminal_supports_unicode?
         
     | 
| 
       120 
121 
     | 
    
         
             
                          if yes
         
     | 
| 
       121 
122 
     | 
    
         
             
                            "\u2713"
         
     | 
| 
       122 
123 
     | 
    
         
             
                          else
         
     | 
| 
         @@ -150,16 +151,9 @@ module Aspera 
     | 
|
| 
       150 
151 
     | 
    
         
             
                  end
         
     | 
| 
       151 
152 
     | 
    
         | 
| 
       152 
153 
     | 
    
         
             
                  # Highlight special values
         
     | 
| 
       153 
     | 
    
         
            -
                  def special_format(what 
     | 
| 
       154 
     | 
    
         
            -
                    result =  
     | 
| 
       155 
     | 
    
         
            -
                     
     | 
| 
       156 
     | 
    
         
            -
                      result = if %w[null empty].any?{|s|what.include?(s)}
         
     | 
| 
       157 
     | 
    
         
            -
                        result.dim
         
     | 
| 
       158 
     | 
    
         
            -
                      else
         
     | 
| 
       159 
     | 
    
         
            -
                        result.reverse_color
         
     | 
| 
       160 
     | 
    
         
            -
                      end
         
     | 
| 
       161 
     | 
    
         
            -
                    end
         
     | 
| 
       162 
     | 
    
         
            -
                    return result
         
     | 
| 
      
 154 
     | 
    
         
            +
                  def special_format(what)
         
     | 
| 
      
 155 
     | 
    
         
            +
                    result = "<#{what}>"
         
     | 
| 
      
 156 
     | 
    
         
            +
                    return %w[null empty].any?{|s|what.include?(s)} ? result.dim : result.reverse_color
         
     | 
| 
       163 
157 
     | 
    
         
             
                  end
         
     | 
| 
       164 
158 
     | 
    
         | 
| 
       165 
159 
     | 
    
         
             
                  # call this after REST calls if several api calls are expected
         
     | 
| 
         @@ -198,7 +192,7 @@ module Aspera 
     | 
|
| 
       198 
192 
     | 
    
         
             
                  end
         
     | 
| 
       199 
193 
     | 
    
         | 
| 
       200 
194 
     | 
    
         
             
                  def declare_options(options)
         
     | 
| 
       201 
     | 
    
         
            -
                    default_table_style = if Environment.terminal_supports_unicode?
         
     | 
| 
      
 195 
     | 
    
         
            +
                    default_table_style = if Environment.instance.terminal_supports_unicode?
         
     | 
| 
       202 
196 
     | 
    
         
             
                      {border: :unicode_round}
         
     | 
| 
       203 
197 
     | 
    
         
             
                    else
         
     | 
| 
       204 
198 
     | 
    
         
             
                      {}
         
     | 
| 
         @@ -326,16 +320,16 @@ module Aspera 
     | 
|
| 
       326 
320 
     | 
    
         
             
                      display_message(:info, special_format('empty')) if @options[:format].eql?(:table)
         
     | 
| 
       327 
321 
     | 
    
         
             
                      return
         
     | 
| 
       328 
322 
     | 
    
         
             
                    end
         
     | 
| 
      
 323 
     | 
    
         
            +
                    # if table has only one element, and only one field, display the value
         
     | 
| 
       329 
324 
     | 
    
         
             
                    if object_array.length == 1 && fields.length == 1
         
     | 
| 
       330 
325 
     | 
    
         
             
                      display_message(:data, object_array.first[fields.first])
         
     | 
| 
       331 
326 
     | 
    
         
             
                      return
         
     | 
| 
       332 
327 
     | 
    
         
             
                    end
         
     | 
| 
       333 
328 
     | 
    
         
             
                    # Special case if only one row (it could be object_list or single_object)
         
     | 
| 
       334 
329 
     | 
    
         
             
                    if @options[:transpose_single] && object_array.length == 1
         
     | 
| 
       335 
     | 
    
         
            -
                      new_columns = %i[key value]
         
     | 
| 
       336 
330 
     | 
    
         
             
                      single = object_array.first
         
     | 
| 
       337 
     | 
    
         
            -
                      object_array = fields.map { |i|  
     | 
| 
       338 
     | 
    
         
            -
                      fields =  
     | 
| 
      
 331 
     | 
    
         
            +
                      object_array = fields.map { |i| FIELD_VALUE_HEADINGS.zip([i, single[i]]).to_h }
         
     | 
| 
      
 332 
     | 
    
         
            +
                      fields = FIELD_VALUE_HEADINGS
         
     | 
| 
       339 
333 
     | 
    
         
             
                    end
         
     | 
| 
       340 
334 
     | 
    
         
             
                    Log.log.debug{Log.dump(:object_array, object_array)}
         
     | 
| 
       341 
335 
     | 
    
         
             
                    # convert data to string, and keep only display fields
         
     | 
| 
         @@ -348,8 +342,18 @@ module Aspera 
     | 
|
| 
       348 
342 
     | 
    
         
             
                        headings:  fields,
         
     | 
| 
       349 
343 
     | 
    
         
             
                        rows:      final_table_rows,
         
     | 
| 
       350 
344 
     | 
    
         
             
                        style:     @options[:table_style]&.symbolize_keys))
         
     | 
| 
      
 345 
     | 
    
         
            +
                    when :multi
         
     | 
| 
      
 346 
     | 
    
         
            +
                      final_table_rows.each do |row|
         
     | 
| 
      
 347 
     | 
    
         
            +
                        Log.log.debug{Log.dump(:row, row)}
         
     | 
| 
      
 348 
     | 
    
         
            +
                        display_message(:data, Terminal::Table.new(
         
     | 
| 
      
 349 
     | 
    
         
            +
                          headings:  FIELD_VALUE_HEADINGS,
         
     | 
| 
      
 350 
     | 
    
         
            +
                          rows:      fields.zip(row),
         
     | 
| 
      
 351 
     | 
    
         
            +
                          style:     @options[:table_style]&.symbolize_keys))
         
     | 
| 
      
 352 
     | 
    
         
            +
                      end
         
     | 
| 
       351 
353 
     | 
    
         
             
                    when :csv
         
     | 
| 
       352 
354 
     | 
    
         
             
                      display_message(:data, final_table_rows.map{|t| t.join(CSV_FIELD_SEPARATOR)}.join(CSV_RECORD_SEPARATOR))
         
     | 
| 
      
 355 
     | 
    
         
            +
                    else
         
     | 
| 
      
 356 
     | 
    
         
            +
                      raise "not expected: #{@options[:format]}"
         
     | 
| 
       353 
357 
     | 
    
         
             
                    end
         
     | 
| 
       354 
358 
     | 
    
         
             
                  end
         
     | 
| 
       355 
359 
     | 
    
         | 
| 
         @@ -420,7 +424,7 @@ module Aspera 
     | 
|
| 
       420 
424 
     | 
    
         
             
                      end
         
     | 
| 
       421 
425 
     | 
    
         
             
                      raise "not url: #{url.class} #{url}" unless url.is_a?(String)
         
     | 
| 
       422 
426 
     | 
    
         
             
                      display_message(:data, status_image(url))
         
     | 
| 
       423 
     | 
    
         
            -
                    when :table, :csv
         
     | 
| 
      
 427 
     | 
    
         
            +
                    when :table, :csv, :multi
         
     | 
| 
       424 
428 
     | 
    
         
             
                      case type
         
     | 
| 
       425 
429 
     | 
    
         
             
                      when :config_over
         
     | 
| 
       426 
430 
     | 
    
         
             
                        display_table(Flattener.new(self).config_over(data), CONF_OVERVIEW_KEYS)
         
     | 
| 
         @@ -452,6 +456,8 @@ module Aspera 
     | 
|
| 
       452 
456 
     | 
    
         
             
                      else
         
     | 
| 
       453 
457 
     | 
    
         
             
                        raise "unknown data type: #{type}"
         
     | 
| 
       454 
458 
     | 
    
         
             
                      end
         
     | 
| 
      
 459 
     | 
    
         
            +
                    else
         
     | 
| 
      
 460 
     | 
    
         
            +
                      raise "not expected: #{@options[:format]}"
         
     | 
| 
       455 
461 
     | 
    
         
             
                    end
         
     | 
| 
       456 
462 
     | 
    
         
             
                  end
         
     | 
| 
       457 
463 
     | 
    
         
             
                end
         
     | 
    
        data/lib/aspera/cli/manager.rb
    CHANGED
    
    | 
         @@ -20,7 +20,7 @@ module Aspera 
     | 
|
| 
       20 
20 
     | 
    
         
             
                    @method = method_name
         
     | 
| 
       21 
21 
     | 
    
         
             
                    @option_name = option_name
         
     | 
| 
       22 
22 
     | 
    
         
             
                    @has_writer = @object.respond_to?(writer_method)
         
     | 
| 
       23 
     | 
    
         
            -
                    Log.log. 
     | 
| 
      
 23 
     | 
    
         
            +
                    Log.log.trace1{"AttrAccessor: #{@option_name}: #{@object.class}.#{@method}: writer=#{@has_writer}"}
         
     | 
| 
       24 
24 
     | 
    
         
             
                    Aspera.assert(@object.respond_to?(@method)) {"#{object} does not respond to #{method_name}"}
         
     | 
| 
       25 
25 
     | 
    
         
             
                  end
         
     | 
| 
       26 
26 
     | 
    
         | 
| 
         @@ -328,7 +328,7 @@ module Aspera 
     | 
|
| 
       328 
328 
     | 
    
         
             
                    if opt[:read_write].eql?(:accessor)
         
     | 
| 
       329 
329 
     | 
    
         
             
                      Aspera.assert_type(handler, Hash)
         
     | 
| 
       330 
330 
     | 
    
         
             
                      Aspera.assert(handler.keys.sort.eql?(%i[m o]))
         
     | 
| 
       331 
     | 
    
         
            -
                      Log.log. 
     | 
| 
      
 331 
     | 
    
         
            +
                      Log.log.trace1{"set attr obj: #{option_symbol} (#{handler[:o]},#{handler[:m]})"}
         
     | 
| 
       332 
332 
     | 
    
         
             
                      opt[:accessor] = AttrAccessor.new(handler[:o], handler[:m], option_symbol)
         
     | 
| 
       333 
333 
     | 
    
         
             
                    end
         
     | 
| 
       334 
334 
     | 
    
         
             
                    set_option(option_symbol, default, where: 'default') unless default.nil?
         
     | 
| 
         @@ -372,7 +372,7 @@ module Aspera 
     | 
|
| 
       372 
372 
     | 
    
         
             
                      @parser.on(*on_args, &block)
         
     | 
| 
       373 
373 
     | 
    
         
             
                    else Aspera.error_unexpected_value(values)
         
     | 
| 
       374 
374 
     | 
    
         
             
                    end
         
     | 
| 
       375 
     | 
    
         
            -
                    Log.log. 
     | 
| 
      
 375 
     | 
    
         
            +
                    Log.log.trace1{"on_args=#{on_args}"}
         
     | 
| 
       376 
376 
     | 
    
         
             
                  end
         
     | 
| 
       377 
377 
     | 
    
         | 
| 
       378 
378 
     | 
    
         
             
                  # Adds each of the keys of specified hash as an option
         
     | 
| 
         @@ -435,7 +435,7 @@ module Aspera 
     | 
|
| 
       435 
435 
     | 
    
         | 
| 
       436 
436 
     | 
    
         
             
                  # removes already known options from the list
         
     | 
| 
       437 
437 
     | 
    
         
             
                  def parse_options!
         
     | 
| 
       438 
     | 
    
         
            -
                    Log.log. 
     | 
| 
      
 438 
     | 
    
         
            +
                    Log.log.trace1('parse_options!'.red)
         
     | 
| 
       439 
439 
     | 
    
         
             
                    # first conf file, then env var
         
     | 
| 
       440 
440 
     | 
    
         
             
                    consume_option_pairs(@option_pairs_batch, 'set')
         
     | 
| 
       441 
441 
     | 
    
         
             
                    consume_option_pairs(@option_pairs_env, 'env')
         
     | 
| 
         @@ -443,16 +443,16 @@ module Aspera 
     | 
|
| 
       443 
443 
     | 
    
         
             
                    unknown_options = []
         
     | 
| 
       444 
444 
     | 
    
         
             
                    begin
         
     | 
| 
       445 
445 
     | 
    
         
             
                      # remove known options one by one, exception if unknown
         
     | 
| 
       446 
     | 
    
         
            -
                      Log.log. 
     | 
| 
      
 446 
     | 
    
         
            +
                      Log.log.trace1('before parse'.red)
         
     | 
| 
       447 
447 
     | 
    
         
             
                      @parser.parse!(@unprocessed_cmd_line_options)
         
     | 
| 
       448 
     | 
    
         
            -
                      Log.log. 
     | 
| 
      
 448 
     | 
    
         
            +
                      Log.log.trace1('After parse'.red)
         
     | 
| 
       449 
449 
     | 
    
         
             
                    rescue OptionParser::InvalidOption => e
         
     | 
| 
       450 
     | 
    
         
            -
                      Log.log. 
     | 
| 
      
 450 
     | 
    
         
            +
                      Log.log.trace1{"InvalidOption #{e}".red}
         
     | 
| 
       451 
451 
     | 
    
         
             
                      # save for later processing
         
     | 
| 
       452 
452 
     | 
    
         
             
                      unknown_options.push(e.args.first)
         
     | 
| 
       453 
453 
     | 
    
         
             
                      retry
         
     | 
| 
       454 
454 
     | 
    
         
             
                    end
         
     | 
| 
       455 
     | 
    
         
            -
                    Log.log. 
     | 
| 
      
 455 
     | 
    
         
            +
                    Log.log.trace1{"remains: #{unknown_options}"}
         
     | 
| 
       456 
456 
     | 
    
         
             
                    # set unprocessed options for next time
         
     | 
| 
       457 
457 
     | 
    
         
             
                    @unprocessed_cmd_line_options = unknown_options
         
     | 
| 
       458 
458 
     | 
    
         
             
                  end
         
     | 
| 
         @@ -538,7 +538,7 @@ module Aspera 
     | 
|
| 
       538 
538 
     | 
    
         
             
                  # @param unprocessed_options [Array] list of options to apply (key_sym,value)
         
     | 
| 
       539 
539 
     | 
    
         
             
                  # @param where [String] where the options come from
         
     | 
| 
       540 
540 
     | 
    
         
             
                  def consume_option_pairs(unprocessed_options, where)
         
     | 
| 
       541 
     | 
    
         
            -
                    Log.log. 
     | 
| 
      
 541 
     | 
    
         
            +
                    Log.log.trace1{"consume_option_pairs: #{where}"}
         
     | 
| 
       542 
542 
     | 
    
         
             
                    options_to_set = {}
         
     | 
| 
       543 
543 
     | 
    
         
             
                    unprocessed_options.each do |k, v|
         
     | 
| 
       544 
544 
     | 
    
         
             
                      if @declared_options.key?(k)
         
     | 
| 
         @@ -548,7 +548,7 @@ module Aspera 
     | 
|
| 
       548 
548 
     | 
    
         
             
                        end
         
     | 
| 
       549 
549 
     | 
    
         
             
                        options_to_set[k] = v
         
     | 
| 
       550 
550 
     | 
    
         
             
                      else
         
     | 
| 
       551 
     | 
    
         
            -
                        Log.log. 
     | 
| 
      
 551 
     | 
    
         
            +
                        Log.log.trace1{"unprocessed: #{k}: #{v}"}
         
     | 
| 
       552 
552 
     | 
    
         
             
                      end
         
     | 
| 
       553 
553 
     | 
    
         
             
                    end
         
     | 
| 
       554 
554 
     | 
    
         
             
                    options_to_set.each do |k, v|
         
     | 
    
        data/lib/aspera/cli/plugin.rb
    CHANGED
    
    | 
         @@ -5,7 +5,7 @@ require 'aspera/assert' 
     | 
|
| 
       5 
5 
     | 
    
         | 
| 
       6 
6 
     | 
    
         
             
            module Aspera
         
     | 
| 
       7 
7 
     | 
    
         
             
              module Cli
         
     | 
| 
       8 
     | 
    
         
            -
                #  
     | 
| 
      
 8 
     | 
    
         
            +
                # Base class for plugins
         
     | 
| 
       9 
9 
     | 
    
         
             
                class Plugin
         
     | 
| 
       10 
10 
     | 
    
         
             
                  # operations without id
         
     | 
| 
       11 
11 
     | 
    
         
             
                  GLOBAL_OPS = %i[create list].freeze
         
     | 
| 
         @@ -53,8 +53,8 @@ module Aspera 
     | 
|
| 
       53 
53 
     | 
    
         
             
                    options.parser.separator('OPTIONS:')
         
     | 
| 
       54 
54 
     | 
    
         
             
                  end
         
     | 
| 
       55 
55 
     | 
    
         | 
| 
      
 56 
     | 
    
         
            +
                  # @return a hash of instance variables
         
     | 
| 
       56 
57 
     | 
    
         
             
                  def init_params
         
     | 
| 
       57 
     | 
    
         
            -
                    # return a hash of instance variables
         
     | 
| 
       58 
58 
     | 
    
         
             
                    INIT_PARAMS.map{|p| [p, instance_variable_get("@#{p}".to_sym)]}.to_h
         
     | 
| 
       59 
59 
     | 
    
         
             
                  end
         
     | 
| 
       60 
60 
     | 
    
         | 
| 
         @@ -3,7 +3,7 @@ 
     | 
|
| 
       3 
3 
     | 
    
         
             
            require 'singleton'
         
     | 
| 
       4 
4 
     | 
    
         
             
            module Aspera
         
     | 
| 
       5 
5 
     | 
    
         
             
              module Cli
         
     | 
| 
       6 
     | 
    
         
            -
                #  
     | 
| 
      
 6 
     | 
    
         
            +
                # Instantiate plugin from well-known locations
         
     | 
| 
       7 
7 
     | 
    
         
             
                class PluginFactory
         
     | 
| 
       8 
8 
     | 
    
         
             
                  include Singleton
         
     | 
| 
       9 
9 
     | 
    
         | 
| 
         @@ -19,14 +19,17 @@ module Aspera 
     | 
|
| 
       19 
19 
     | 
    
         
             
                    @plugins = {}
         
     | 
| 
       20 
20 
     | 
    
         
             
                  end
         
     | 
| 
       21 
21 
     | 
    
         | 
| 
      
 22 
     | 
    
         
            +
                  # @return list of registered plugins
         
     | 
| 
       22 
23 
     | 
    
         
             
                  def plugin_list
         
     | 
| 
       23 
24 
     | 
    
         
             
                    @plugins.keys
         
     | 
| 
       24 
25 
     | 
    
         
             
                  end
         
     | 
| 
       25 
26 
     | 
    
         | 
| 
      
 27 
     | 
    
         
            +
                  # @return path to source file of plugin
         
     | 
| 
       26 
28 
     | 
    
         
             
                  def plugin_source(plugin_name_sym)
         
     | 
| 
       27 
29 
     | 
    
         
             
                    @plugins[plugin_name_sym][:source]
         
     | 
| 
       28 
30 
     | 
    
         
             
                  end
         
     | 
| 
       29 
31 
     | 
    
         | 
| 
      
 32 
     | 
    
         
            +
                  # add a folder to the list of folders to look for plugins
         
     | 
| 
       30 
33 
     | 
    
         
             
                  def add_lookup_folder(folder)
         
     | 
| 
       31 
34 
     | 
    
         
             
                    @lookup_folders.unshift(folder)
         
     | 
| 
       32 
35 
     | 
    
         
             
                  end
         
     | 
| 
         @@ -43,6 +46,7 @@ module Aspera 
     | 
|
| 
       43 
46 
     | 
    
         
             
                    end
         
     | 
| 
       44 
47 
     | 
    
         
             
                  end
         
     | 
| 
       45 
48 
     | 
    
         | 
| 
      
 49 
     | 
    
         
            +
                  # @return Class object for plugin
         
     | 
| 
       46 
50 
     | 
    
         
             
                  def plugin_class(plugin_name_sym)
         
     | 
| 
       47 
51 
     | 
    
         
             
                    raise "ERROR: plugin not found: #{plugin_name_sym}" unless @plugins.key?(plugin_name_sym)
         
     | 
| 
       48 
52 
     | 
    
         
             
                    require @plugins[plugin_name_sym][:require_stanza]
         
     | 
| 
         @@ -50,6 +54,9 @@ module Aspera 
     | 
|
| 
       50 
54 
     | 
    
         
             
                    return Object.const_get("#{Module.nesting[1]}::#{PLUGINS_MODULE}::#{plugin_name_sym.to_s.capitalize}")
         
     | 
| 
       51 
55 
     | 
    
         
             
                  end
         
     | 
| 
       52 
56 
     | 
    
         | 
| 
      
 57 
     | 
    
         
            +
                  # Create specified plugin
         
     | 
| 
      
 58 
     | 
    
         
            +
                  # @param plugin_name_sym [Symbol] name of plugin
         
     | 
| 
      
 59 
     | 
    
         
            +
                  # @param args [Hash] arguments to pass to plugin constructor
         
     | 
| 
       53 
60 
     | 
    
         
             
                  def create(plugin_name_sym, **args)
         
     | 
| 
       54 
61 
     | 
    
         
             
                    # TODO: check that ancestor is Plugin?
         
     | 
| 
       55 
62 
     | 
    
         
             
                    plugin_class(plugin_name_sym).new(**args)
         
     | 
| 
         @@ -57,6 +64,8 @@ module Aspera 
     | 
|
| 
       57 
64 
     | 
    
         | 
| 
       58 
65 
     | 
    
         
             
                  private
         
     | 
| 
       59 
66 
     | 
    
         | 
| 
      
 67 
     | 
    
         
            +
                  # add plugin information to list
         
     | 
| 
      
 68 
     | 
    
         
            +
                  # @param path [String] path to plugin source file
         
     | 
| 
       60 
69 
     | 
    
         
             
                  def add_plugin_info(path)
         
     | 
| 
       61 
70 
     | 
    
         
             
                    raise "ERROR: plugin path must end with #{RUBY_FILE_EXT}" if !path.end_with?(RUBY_FILE_EXT)
         
     | 
| 
       62 
71 
     | 
    
         
             
                    plugin_symbol = File.basename(path, RUBY_FILE_EXT).to_sym
         
     | 
| 
         @@ -281,6 +281,8 @@ module Aspera 
     | 
|
| 
       281 
281 
     | 
    
         
             
                    attr_reader :option_ignore_cert_host_port, :progress_bar
         
     | 
| 
       282 
282 
     | 
    
         | 
| 
       283 
283 
     | 
    
         
             
                    # add files, folders or default locations to the certificate store
         
     | 
| 
      
 284 
     | 
    
         
            +
                    # @param path_list [Array<String>] list of paths to add
         
     | 
| 
      
 285 
     | 
    
         
            +
                    # @return the list of paths
         
     | 
| 
       284 
286 
     | 
    
         
             
                    def trusted_cert_locations=(path_list)
         
     | 
| 
       285 
287 
     | 
    
         
             
                      path_list = [path_list] unless path_list.is_a?(Array)
         
     | 
| 
       286 
288 
     | 
    
         
             
                      Aspera.assert_type(path_list, Array){'cert locations'}
         
     | 
| 
         @@ -296,10 +298,10 @@ module Aspera 
     | 
|
| 
       296 
298 
     | 
    
         
             
                        Log.log.debug{"Adding cert location: #{path}"}
         
     | 
| 
       297 
299 
     | 
    
         
             
                        if path.eql?(SpecialValues::DEF)
         
     | 
| 
       298 
300 
     | 
    
         
             
                          @certificate_store.set_default_paths
         
     | 
| 
       299 
     | 
    
         
            -
                          paths_to_add = [
         
     | 
| 
       300 
     | 
    
         
            -
             
     | 
| 
       301 
     | 
    
         
            -
             
     | 
| 
       302 
     | 
    
         
            -
                           
     | 
| 
      
 301 
     | 
    
         
            +
                          paths_to_add = [OpenSSL::X509::DEFAULT_CERT_DIR]
         
     | 
| 
      
 302 
     | 
    
         
            +
                          # JRuby cert file seems not to be PEM
         
     | 
| 
      
 303 
     | 
    
         
            +
                          paths_to_add.push(OpenSSL::X509::DEFAULT_CERT_FILE) unless defined?(JRUBY_VERSION)
         
     | 
| 
      
 304 
     | 
    
         
            +
                          paths_to_add.select!{|f|File.exist?(f)}
         
     | 
| 
       303 
305 
     | 
    
         
             
                        elsif File.file?(path)
         
     | 
| 
       304 
306 
     | 
    
         
             
                          @certificate_store.add_file(path)
         
     | 
| 
       305 
307 
     | 
    
         
             
                        elsif File.directory?(path)
         
     | 
| 
         @@ -578,7 +580,7 @@ module Aspera 
     | 
|
| 
       578 
580 
     | 
    
         
             
                        @config_checksum_on_disk = config_checksum
         
     | 
| 
       579 
581 
     | 
    
         
             
                      end
         
     | 
| 
       580 
582 
     | 
    
         
             
                      files_to_copy = []
         
     | 
| 
       581 
     | 
    
         
            -
                      Log.log. 
     | 
| 
      
 583 
     | 
    
         
            +
                      Log.log.trace1{Log.dump('Available_presets', @config_presets)}
         
     | 
| 
       582 
584 
     | 
    
         
             
                      Aspera.assert_type(@config_presets, Hash){'config file YAML'}
         
     | 
| 
       583 
585 
     | 
    
         
             
                      # check there is at least the config section
         
     | 
| 
       584 
586 
     | 
    
         
             
                      Aspera.assert(@config_presets.key?(CONF_PRESET_CONFIG)){"Cannot find key: #{CONF_PRESET_CONFIG}"}
         
     | 
| 
         @@ -699,8 +701,7 @@ module Aspera 
     | 
|
| 
       699 
701 
     | 
    
         
             
                        return execute_connect_action
         
     | 
| 
       700 
702 
     | 
    
         
             
                      when :use
         
     | 
| 
       701 
703 
     | 
    
         
             
                        ascp_path = options.get_next_argument('path to ascp')
         
     | 
| 
       702 
     | 
    
         
            -
                         
     | 
| 
       703 
     | 
    
         
            -
                        formatter.display_status("ascp version: #{ascp_version}")
         
     | 
| 
      
 704 
     | 
    
         
            +
                        formatter.display_status("ascp version: #{Ascp::Installation.instance.get_ascp_version(ascp_path)}")
         
     | 
| 
       704 
705 
     | 
    
         
             
                        set_global_default(:ascp_path, ascp_path)
         
     | 
| 
       705 
706 
     | 
    
         
             
                        return Main.result_nothing
         
     | 
| 
       706 
707 
     | 
    
         
             
                      when :show
         
     | 
| 
         @@ -729,8 +730,8 @@ module Aspera 
     | 
|
| 
       729 
730 
     | 
    
         
             
                      when :install
         
     | 
| 
       730 
731 
     | 
    
         
             
                        # reset to default location, if older default was used
         
     | 
| 
       731 
732 
     | 
    
         
             
                        Ascp::Installation.instance.sdk_folder = self.class.default_app_main_folder(app_name: APP_NAME_SDK) if @sdk_default_location
         
     | 
| 
       732 
     | 
    
         
            -
                        v = Ascp::Installation.instance.install_sdk(options.get_option(:sdk_url, mandatory: true))
         
     | 
| 
       733 
     | 
    
         
            -
                        return Main.result_status("Installed version #{v}")
         
     | 
| 
      
 733 
     | 
    
         
            +
                        n, v = Ascp::Installation.instance.install_sdk(options.get_option(:sdk_url, mandatory: true))
         
     | 
| 
      
 734 
     | 
    
         
            +
                        return Main.result_status("Installed #{n} version #{v}")
         
     | 
| 
       734 
735 
     | 
    
         
             
                      when :spec
         
     | 
| 
       735 
736 
     | 
    
         
             
                        return {
         
     | 
| 
       736 
737 
     | 
    
         
             
                          type:   :object_list,
         
     | 
| 
         @@ -871,7 +872,9 @@ module Aspera 
     | 
|
| 
       871 
872 
     | 
    
         
             
                      check_update
         
     | 
| 
       872 
873 
     | 
    
         
             
                      initdemo
         
     | 
| 
       873 
874 
     | 
    
         
             
                      vault
         
     | 
| 
       874 
     | 
    
         
            -
                      throw 
     | 
| 
      
 875 
     | 
    
         
            +
                      throw
         
     | 
| 
      
 876 
     | 
    
         
            +
                      platform
         
     | 
| 
      
 877 
     | 
    
         
            +
                    ].freeze
         
     | 
| 
       875 
878 
     | 
    
         | 
| 
       876 
879 
     | 
    
         
             
                    # Main action procedure for plugin
         
     | 
| 
       877 
880 
     | 
    
         
             
                    def execute_action
         
     | 
| 
         @@ -1015,6 +1018,8 @@ module Aspera 
     | 
|
| 
       1015 
1018 
     | 
    
         
             
                        exception_class = Object.const_get(exception_class_name)
         
     | 
| 
       1016 
1019 
     | 
    
         
             
                        Aspera.assert(exception_class <= Exception){"#{exception_class} is not an exception: #{exception_class.class}"}
         
     | 
| 
       1017 
1020 
     | 
    
         
             
                        raise exception_class, exception_text
         
     | 
| 
      
 1021 
     | 
    
         
            +
                      when :platform
         
     | 
| 
      
 1022 
     | 
    
         
            +
                        return Main.result_status(Environment.architecture)
         
     | 
| 
       1018 
1023 
     | 
    
         
             
                      else Aspera.error_unreachable_line
         
     | 
| 
       1019 
1024 
     | 
    
         
             
                      end
         
     | 
| 
       1020 
1025 
     | 
    
         
             
                    end
         
     | 
| 
         @@ -531,16 +531,17 @@ module Aspera 
     | 
|
| 
       531 
531 
     | 
    
         
             
                        # if a single file: split into folder and path
         
     | 
| 
       532 
532 
     | 
    
         
             
                        apifid = @api_node.resolve_api_fid(top_file_id, source_folder)
         
     | 
| 
       533 
533 
     | 
    
         
             
                        if source_paths.empty?
         
     | 
| 
      
 534 
     | 
    
         
            +
                          # get precise info in this element
         
     | 
| 
       534 
535 
     | 
    
         
             
                          file_info = apifid[:api].read("files/#{apifid[:file_id]}")[:data]
         
     | 
| 
       535 
536 
     | 
    
         
             
                          case file_info['type']
         
     | 
| 
       536 
537 
     | 
    
         
             
                          when 'file'
         
     | 
| 
       537 
538 
     | 
    
         
             
                            # if the single source is a file, we need to split into folder path and filename
         
     | 
| 
       538 
539 
     | 
    
         
             
                            src_dir_elements = source_folder.split(Api::Node::PATH_SEPARATOR)
         
     | 
| 
       539 
     | 
    
         
            -
                            # filename is the last one
         
     | 
| 
      
 540 
     | 
    
         
            +
                            # filename is the last one, source folder is what remains
         
     | 
| 
       540 
541 
     | 
    
         
             
                            source_paths = [{'source' => src_dir_elements.pop}]
         
     | 
| 
       541 
     | 
    
         
            -
                            #  
     | 
| 
      
 542 
     | 
    
         
            +
                            # add trailing / so that link is resolved, if it's a shared folder
         
     | 
| 
      
 543 
     | 
    
         
            +
                            src_dir_elements.push('')
         
     | 
| 
       542 
544 
     | 
    
         
             
                            source_folder = src_dir_elements.join(Api::Node::PATH_SEPARATOR)
         
     | 
| 
       543 
     | 
    
         
            -
                            # TODO: instead of creating a new object, use the same, and change file id with parent folder id ? possible ?
         
     | 
| 
       544 
545 
     | 
    
         
             
                            apifid = @api_node.resolve_api_fid(top_file_id, source_folder)
         
     | 
| 
       545 
546 
     | 
    
         
             
                          when 'link', 'folder'
         
     | 
| 
       546 
547 
     | 
    
         
             
                            # single source is 'folder' or 'link'
         
     | 
| 
         @@ -176,7 +176,7 @@ module Aspera 
     | 
|
| 
       176 
176 
     | 
    
         
             
                    def execute_transfer(command, transfer_spec)
         
     | 
| 
       177 
177 
     | 
    
         
             
                      case command
         
     | 
| 
       178 
178 
     | 
    
         
             
                      when :upload, :download
         
     | 
| 
       179 
     | 
    
         
            -
                        Transfer::Spec. 
     | 
| 
      
 179 
     | 
    
         
            +
                        transfer_spec['direction'] = Transfer::Spec.transfer_type_to_direction(command)
         
     | 
| 
       180 
180 
     | 
    
         
             
                        return Main.result_transfer(transfer.start(transfer_spec))
         
     | 
| 
       181 
181 
     | 
    
         
             
                      when :sync
         
     | 
| 
       182 
182 
     | 
    
         
             
                        # lets ignore the arguments provided by execute_sync_action, we just give the transfer spec
         
     | 
| 
         @@ -7,7 +7,10 @@ module Aspera 
     | 
|
| 
       7 
7 
     | 
    
         
             
                module Plugins
         
     | 
| 
       8 
8 
     | 
    
         
             
                  # Plugin for Aspera Shares v1
         
     | 
| 
       9 
9 
     | 
    
         
             
                  class Shares < Cli::BasicAuthPlugin
         
     | 
| 
       10 
     | 
    
         
            -
                     
     | 
| 
      
 10 
     | 
    
         
            +
                    # path for node API after base url
         
     | 
| 
      
 11 
     | 
    
         
            +
                    NODE_API_PATH = 'node_api'
         
     | 
| 
      
 12 
     | 
    
         
            +
                    # path for node admin after base url
         
     | 
| 
      
 13 
     | 
    
         
            +
                    ADMIN_API_PATH = 'api/v1'
         
     | 
| 
       11 
14 
     | 
    
         
             
                    class << self
         
     | 
| 
       12 
15 
     | 
    
         
             
                      def detect(address_or_url)
         
     | 
| 
       13 
16 
     | 
    
         
             
                        address_or_url = "https://#{address_or_url}" unless address_or_url.match?(%r{^[a-z]{1,6}://})
         
     | 
| 
         @@ -16,7 +19,7 @@ module Aspera 
     | 
|
| 
       16 
19 
     | 
    
         
             
                        begin
         
     | 
| 
       17 
20 
     | 
    
         
             
                          # shall fail: shares requires auth, but we check error message
         
     | 
| 
       18 
21 
     | 
    
         
             
                          # TODO: use ping instead ?
         
     | 
| 
       19 
     | 
    
         
            -
                          api.read("#{ 
     | 
| 
      
 22 
     | 
    
         
            +
                          api.read("#{NODE_API_PATH}/app")
         
     | 
| 
       20 
23 
     | 
    
         
             
                        rescue RestCallError => e
         
     | 
| 
       21 
24 
     | 
    
         
             
                          if e.response.code.to_s.eql?('401') && e.response.body.eql?('{"error":{"user_message":"API user authentication failed"}}')
         
     | 
| 
       22 
25 
     | 
    
         
             
                            found = true
         
     | 
| 
         @@ -65,7 +68,7 @@ module Aspera 
     | 
|
| 
       65 
68 
     | 
    
         
             
                        nagios = Nagios.new
         
     | 
| 
       66 
69 
     | 
    
         
             
                        begin
         
     | 
| 
       67 
70 
     | 
    
         
             
                          res = Rest
         
     | 
| 
       68 
     | 
    
         
            -
                            .new(base_url: "#{options.get_option(:url, mandatory: true)}/#{ 
     | 
| 
      
 71 
     | 
    
         
            +
                            .new(base_url: "#{options.get_option(:url, mandatory: true)}/#{NODE_API_PATH}")
         
     | 
| 
       69 
72 
     | 
    
         
             
                            .call(
         
     | 
| 
       70 
73 
     | 
    
         
             
                              operation: 'GET',
         
     | 
| 
       71 
74 
     | 
    
         
             
                              subpath: 'ping',
         
     | 
| 
         @@ -77,13 +80,13 @@ module Aspera 
     | 
|
| 
       77 
80 
     | 
    
         
             
                        end
         
     | 
| 
       78 
81 
     | 
    
         
             
                        return nagios.result
         
     | 
| 
       79 
82 
     | 
    
         
             
                      when :repository, :files
         
     | 
| 
       80 
     | 
    
         
            -
                        api_shares_node = basic_auth_api( 
     | 
| 
      
 83 
     | 
    
         
            +
                        api_shares_node = basic_auth_api(NODE_API_PATH)
         
     | 
| 
       81 
84 
     | 
    
         
             
                        repo_command = options.get_next_command(Node::COMMANDS_SHARES)
         
     | 
| 
       82 
85 
     | 
    
         
             
                        return Node
         
     | 
| 
       83 
86 
     | 
    
         
             
                            .new(**init_params, api: api_shares_node)
         
     | 
| 
       84 
87 
     | 
    
         
             
                            .execute_action(repo_command)
         
     | 
| 
       85 
88 
     | 
    
         
             
                      when :admin
         
     | 
| 
       86 
     | 
    
         
            -
                        api_shares_admin = basic_auth_api( 
     | 
| 
      
 89 
     | 
    
         
            +
                        api_shares_admin = basic_auth_api(ADMIN_API_PATH)
         
     | 
| 
       87 
90 
     | 
    
         
             
                        admin_command = options.get_next_command(%i[node share transfer_settings user group].freeze)
         
     | 
| 
       88 
91 
     | 
    
         
             
                        case admin_command
         
     | 
| 
       89 
92 
     | 
    
         
             
                        when :node
         
     | 
| 
         @@ -92,8 +95,9 @@ module Aspera 
     | 
|
| 
       92 
95 
     | 
    
         
             
                          share_command = options.get_next_command(%i[user_permissions group_permissions].concat(Plugin::ALL_OPS))
         
     | 
| 
       93 
96 
     | 
    
         
             
                          case share_command
         
     | 
| 
       94 
97 
     | 
    
         
             
                          when *Plugin::ALL_OPS
         
     | 
| 
       95 
     | 
    
         
            -
                            return entity_command( 
     | 
| 
       96 
     | 
    
         
            -
             
     | 
| 
      
 98 
     | 
    
         
            +
                            return entity_command(
         
     | 
| 
      
 99 
     | 
    
         
            +
                              share_command, api_shares_admin, 'data/shares',
         
     | 
| 
      
 100 
     | 
    
         
            +
                              display_fields: %w[id name node_id directory percent_free])
         
     | 
| 
       97 
101 
     | 
    
         
             
                          when :user_permissions, :group_permissions
         
     | 
| 
       98 
102 
     | 
    
         
             
                            share_id = instance_identifier
         
     | 
| 
       99 
103 
     | 
    
         
             
                            return entity_action(api_shares_admin, "data/shares/#{share_id}/#{share_command}")
         
     |