aspera-cli 4.15.0 → 4.16.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/BUGS.md +29 -3
 - data/CHANGELOG.md +292 -228
 - data/CONTRIBUTING.md +69 -18
 - data/README.md +1102 -952
 - data/bin/ascli +13 -31
 - data/bin/asession +3 -1
 - data/examples/dascli +2 -2
 - data/lib/aspera/aoc.rb +28 -33
 - data/lib/aspera/ascmd.rb +3 -6
 - data/lib/aspera/assert.rb +45 -0
 - data/lib/aspera/cli/extended_value.rb +5 -5
 - data/lib/aspera/cli/formatter.rb +26 -13
 - data/lib/aspera/cli/hints.rb +4 -3
 - data/lib/aspera/cli/main.rb +16 -3
 - data/lib/aspera/cli/manager.rb +45 -36
 - data/lib/aspera/cli/plugin.rb +20 -13
 - data/lib/aspera/cli/plugins/aoc.rb +103 -73
 - data/lib/aspera/cli/plugins/ats.rb +4 -3
 - data/lib/aspera/cli/plugins/config.rb +114 -119
 - data/lib/aspera/cli/plugins/cos.rb +2 -2
 - data/lib/aspera/cli/plugins/faspex.rb +23 -19
 - data/lib/aspera/cli/plugins/faspex5.rb +75 -43
 - data/lib/aspera/cli/plugins/node.rb +28 -15
 - data/lib/aspera/cli/plugins/orchestrator.rb +4 -2
 - data/lib/aspera/cli/plugins/preview.rb +9 -7
 - data/lib/aspera/cli/plugins/server.rb +6 -3
 - data/lib/aspera/cli/plugins/shares.rb +30 -26
 - data/lib/aspera/cli/sync_actions.rb +9 -9
 - data/lib/aspera/cli/transfer_agent.rb +21 -14
 - data/lib/aspera/cli/transfer_progress.rb +2 -3
 - data/lib/aspera/cli/version.rb +1 -1
 - data/lib/aspera/command_line_builder.rb +13 -11
 - data/lib/aspera/cos_node.rb +3 -2
 - data/lib/aspera/coverage.rb +22 -0
 - data/lib/aspera/data_repository.rb +33 -2
 - data/lib/aspera/environment.rb +4 -2
 - data/lib/aspera/fasp/{agent_aspera.rb → agent_alpha.rb} +29 -39
 - data/lib/aspera/fasp/agent_base.rb +17 -7
 - data/lib/aspera/fasp/agent_direct.rb +88 -84
 - data/lib/aspera/fasp/agent_httpgw.rb +4 -3
 - data/lib/aspera/fasp/agent_node.rb +3 -2
 - data/lib/aspera/fasp/agent_trsdk.rb +79 -37
 - data/lib/aspera/fasp/installation.rb +51 -12
 - data/lib/aspera/fasp/management.rb +11 -6
 - data/lib/aspera/fasp/parameters.rb +53 -47
 - data/lib/aspera/fasp/resume_policy.rb +7 -5
 - data/lib/aspera/fasp/sync.rb +273 -0
 - data/lib/aspera/fasp/transfer_spec.rb +10 -8
 - data/lib/aspera/fasp/uri.rb +2 -2
 - data/lib/aspera/faspex_gw.rb +11 -8
 - data/lib/aspera/faspex_postproc.rb +6 -5
 - data/lib/aspera/id_generator.rb +3 -1
 - data/lib/aspera/json_rpc.rb +10 -8
 - data/lib/aspera/keychain/encrypted_hash.rb +46 -11
 - data/lib/aspera/keychain/macos_security.rb +15 -13
 - data/lib/aspera/log.rb +4 -3
 - data/lib/aspera/nagios.rb +7 -2
 - data/lib/aspera/node.rb +17 -16
 - data/lib/aspera/node_simulator.rb +214 -0
 - data/lib/aspera/oauth.rb +22 -19
 - data/lib/aspera/persistency_action_once.rb +13 -14
 - data/lib/aspera/persistency_folder.rb +3 -2
 - data/lib/aspera/preview/file_types.rb +53 -267
 - data/lib/aspera/preview/generator.rb +7 -5
 - data/lib/aspera/preview/terminal.rb +14 -5
 - data/lib/aspera/preview/utils.rb +8 -7
 - data/lib/aspera/proxy_auto_config.rb +6 -3
 - data/lib/aspera/rest.rb +29 -13
 - data/lib/aspera/rest_error_analyzer.rb +1 -0
 - data/lib/aspera/rest_errors_aspera.rb +2 -0
 - data/lib/aspera/secret_hider.rb +5 -2
 - data/lib/aspera/ssh.rb +10 -8
 - data/lib/aspera/temp_file_manager.rb +1 -1
 - data/lib/aspera/web_server_simple.rb +2 -1
 - data.tar.gz.sig +0 -0
 - metadata +96 -45
 - metadata.gz.sig +0 -0
 - data/lib/aspera/sync.rb +0 -219
 
    
        data/bin/ascli
    CHANGED
    
    | 
         @@ -3,36 +3,18 @@ 
     | 
|
| 
       3 
3 
     | 
    
         | 
| 
       4 
4 
     | 
    
         
             
            Encoding.default_internal = Encoding::UTF_8
         
     | 
| 
       5 
5 
     | 
    
         
             
            Encoding.default_external = Encoding::UTF_8
         
     | 
| 
       6 
     | 
    
         
            -
             
     | 
| 
       7 
     | 
    
         
            -
            if ENV.key?('ENABLE_COVERAGE')
         
     | 
| 
       8 
     | 
    
         
            -
              require 'simplecov'
         
     | 
| 
       9 
     | 
    
         
            -
              require 'securerandom'
         
     | 
| 
       10 
     | 
    
         
            -
              # compute gem source root based on this script location, assuming it is in bin/
         
     | 
| 
       11 
     | 
    
         
            -
              # use dirname instead of gsub, in case folder separator is not /
         
     | 
| 
       12 
     | 
    
         
            -
              development_root = File.dirname(File.dirname(File.realpath(__FILE__)))
         
     | 
| 
       13 
     | 
    
         
            -
              SimpleCov.root(development_root)
         
     | 
| 
       14 
     | 
    
         
            -
              SimpleCov.enable_for_subprocesses if SimpleCov.respond_to?(:enable_for_subprocesses)
         
     | 
| 
       15 
     | 
    
         
            -
              # keep cache data for 1 day (must be longer that time to run the whole test suite)
         
     | 
| 
       16 
     | 
    
         
            -
              SimpleCov.merge_timeout(86400)
         
     | 
| 
       17 
     | 
    
         
            -
              SimpleCov.command_name(SecureRandom.uuid)
         
     | 
| 
       18 
     | 
    
         
            -
              SimpleCov.at_exit do
         
     | 
| 
       19 
     | 
    
         
            -
                original_file_descriptor = $stdout
         
     | 
| 
       20 
     | 
    
         
            -
                $stdout.reopen(File.join(development_root, 'simplecov.log'))
         
     | 
| 
       21 
     | 
    
         
            -
                SimpleCov.result.format!
         
     | 
| 
       22 
     | 
    
         
            -
                $stdout.reopen(original_file_descriptor)
         
     | 
| 
       23 
     | 
    
         
            -
              end
         
     | 
| 
       24 
     | 
    
         
            -
              SimpleCov.start
         
     | 
| 
       25 
     | 
    
         
            -
            end
         
     | 
| 
       26 
     | 
    
         
            -
            # if in development, add path to gem
         
     | 
| 
       27 
     | 
    
         
            -
            #
         
     | 
| 
      
 6 
     | 
    
         
            +
             
     | 
| 
       28 
7 
     | 
    
         
             
            begin
         
     | 
| 
       29 
     | 
    
         
            -
               
     | 
| 
       30 
     | 
    
         
            -
             
     | 
| 
       31 
     | 
    
         
            -
               
     | 
| 
       32 
     | 
    
         
            -
             
     | 
| 
       33 
     | 
    
         
            -
               
     | 
| 
       34 
     | 
    
         
            -
             
     | 
| 
      
 8 
     | 
    
         
            +
              gem_lib_folder = File.join(File.dirname(File.dirname(File.realpath(__FILE__))), 'lib')
         
     | 
| 
      
 9 
     | 
    
         
            +
              Kernel.load(File.join(gem_lib_folder, 'aspera/coverage.rb'))
         
     | 
| 
      
 10 
     | 
    
         
            +
              begin
         
     | 
| 
      
 11 
     | 
    
         
            +
                require 'aspera/cli/main'
         
     | 
| 
      
 12 
     | 
    
         
            +
              rescue LoadError
         
     | 
| 
      
 13 
     | 
    
         
            +
                # if in development, add path toward gem
         
     | 
| 
      
 14 
     | 
    
         
            +
                $LOAD_PATH.unshift(gem_lib_folder)
         
     | 
| 
      
 15 
     | 
    
         
            +
                require 'aspera/cli/main'
         
     | 
| 
      
 16 
     | 
    
         
            +
              end
         
     | 
| 
      
 17 
     | 
    
         
            +
              require 'aspera/environment'
         
     | 
| 
      
 18 
     | 
    
         
            +
              Aspera::Environment.fix_home
         
     | 
| 
      
 19 
     | 
    
         
            +
              Aspera::Cli::Main.new(ARGV).process_command_line
         
     | 
| 
       35 
20 
     | 
    
         
             
            end
         
     | 
| 
       36 
     | 
    
         
            -
            require 'aspera/environment'
         
     | 
| 
       37 
     | 
    
         
            -
            Aspera::Environment.fix_home
         
     | 
| 
       38 
     | 
    
         
            -
            Aspera::Cli::Main.new(ARGV).process_command_line
         
     | 
    
        data/bin/asession
    CHANGED
    
    | 
         @@ -75,10 +75,12 @@ client = Aspera::Fasp::AgentDirect.new({quiet: true}) 
     | 
|
| 
       75 
75 
     | 
    
         
             
            job_id = client.start_transfer(transfer_spec)
         
     | 
| 
       76 
76 
     | 
    
         
             
            # async commands
         
     | 
| 
       77 
77 
     | 
    
         
             
            Thread.new do
         
     | 
| 
      
 78 
     | 
    
         
            +
              # we assume here a single session
         
     | 
| 
      
 79 
     | 
    
         
            +
              session_id = client.sessions_by_job(job_id).first
         
     | 
| 
       78 
80 
     | 
    
         
             
              begin # rubocop:disable Style/RedundantBegin
         
     | 
| 
       79 
81 
     | 
    
         
             
                loop do
         
     | 
| 
       80 
82 
     | 
    
         
             
                  data = JSON.parse($stdin.gets)
         
     | 
| 
       81 
     | 
    
         
            -
                  client.send_command( 
     | 
| 
      
 83 
     | 
    
         
            +
                  client.send_command(session_id, data)
         
     | 
| 
       82 
84 
     | 
    
         
             
                end
         
     | 
| 
       83 
85 
     | 
    
         
             
              rescue
         
     | 
| 
       84 
86 
     | 
    
         
             
                Process.exit(1)
         
     | 
    
        data/examples/dascli
    CHANGED
    
    | 
         @@ -7,7 +7,7 @@ 
     | 
|
| 
       7 
7 
     | 
    
         
             
            : "${imgtag=$image:$version}"
         
     | 
| 
       8 
8 
     | 
    
         
             
            # set env var `docker` to podman, to use podman
         
     | 
| 
       9 
9 
     | 
    
         
             
            : "${docker:=docker}"
         
     | 
| 
       10 
     | 
    
         
            -
            # set env var docker_args to add options to docker run (transform var into array) # spellcheck disable=SC2086
         
     | 
| 
      
 10 
     | 
    
         
            +
            # set env var `docker_args` to add options to docker run (then, transform this var into array) # spellcheck disable=SC2086
         
     | 
| 
       11 
11 
     | 
    
         
             
            read -a add_dock_args <<< $docker_args
         
     | 
| 
       12 
12 
     | 
    
         
             
            # set env var ASCLI_HOME to set the config folder on host
         
     | 
| 
       13 
13 
     | 
    
         
             
            : "${ASCLI_HOME:=$HOME/.aspera/ascli}"
         
     | 
| 
         @@ -24,7 +24,7 @@ exec $docker run \ 
     | 
|
| 
       24 
24 
     | 
    
         
             
            --interactive \
         
     | 
| 
       25 
25 
     | 
    
         
             
            --user root \
         
     | 
| 
       26 
26 
     | 
    
         
             
            --env ASCLI_HOME="$ascli_home_container" \
         
     | 
| 
       27 
     | 
    
         
            -
            --volume "$ASCLI_HOME:$ascli_home_container" \
         
     | 
| 
      
 27 
     | 
    
         
            +
            --volume "$ASCLI_HOME:$ascli_home_container:z" \
         
     | 
| 
       28 
28 
     | 
    
         
             
            "${add_dock_args[@]}" \
         
     | 
| 
       29 
29 
     | 
    
         
             
            "$imgtag" \
         
     | 
| 
       30 
30 
     | 
    
         
             
            "$@"
         
     | 
    
        data/lib/aspera/aoc.rb
    CHANGED
    
    | 
         @@ -1,6 +1,7 @@ 
     | 
|
| 
       1 
1 
     | 
    
         
             
            # frozen_string_literal: true
         
     | 
| 
       2 
2 
     | 
    
         | 
| 
       3 
3 
     | 
    
         
             
            require 'aspera/log'
         
     | 
| 
      
 4 
     | 
    
         
            +
            require 'aspera/assert'
         
     | 
| 
       4 
5 
     | 
    
         
             
            require 'aspera/rest'
         
     | 
| 
       5 
6 
     | 
    
         
             
            require 'aspera/hash_ext'
         
     | 
| 
       6 
7 
     | 
    
         
             
            require 'aspera/data_repository'
         
     | 
| 
         @@ -31,10 +32,9 @@ module Aspera 
     | 
|
| 
       31 
32 
     | 
    
         
             
                PROD_DOMAIN = 'ibmaspera.com' # cspell:disable-line
         
     | 
| 
       32 
33 
     | 
    
         
             
                # to avoid infinite loop in pub link redirection
         
     | 
| 
       33 
34 
     | 
    
         
             
                MAX_AOC_URL_REDIRECT = 10
         
     | 
| 
      
 35 
     | 
    
         
            +
                CLIENT_ID_PREFIX = 'aspera.'
         
     | 
| 
       34 
36 
     | 
    
         
             
                # Well-known AoC globals client apps
         
     | 
| 
       35 
     | 
    
         
            -
                GLOBAL_CLIENT_APPS =  
     | 
| 
       36 
     | 
    
         
            -
                # index offset in data repository of client app
         
     | 
| 
       37 
     | 
    
         
            -
                DATA_REPO_INDEX_START = 4
         
     | 
| 
      
 37 
     | 
    
         
            +
                GLOBAL_CLIENT_APPS = DataRepository::ELEMENTS.select{|i|i.to_s.start_with?(CLIENT_ID_PREFIX)}.freeze
         
     | 
| 
       38 
38 
     | 
    
         
             
                # cookie prefix so that console can decode identity
         
     | 
| 
       39 
39 
     | 
    
         
             
                COOKIE_PREFIX_CONSOLE_AOC = 'aspera.aoc'
         
     | 
| 
       40 
40 
     | 
    
         
             
                # path in URL of public links
         
     | 
| 
         @@ -50,7 +50,6 @@ module Aspera 
     | 
|
| 
       50 
50 
     | 
    
         | 
| 
       51 
51 
     | 
    
         
             
                private_constant :MAX_AOC_URL_REDIRECT,
         
     | 
| 
       52 
52 
     | 
    
         
             
                  :GLOBAL_CLIENT_APPS,
         
     | 
| 
       53 
     | 
    
         
            -
                  :DATA_REPO_INDEX_START,
         
     | 
| 
       54 
53 
     | 
    
         
             
                  :COOKIE_PREFIX_CONSOLE_AOC,
         
     | 
| 
       55 
54 
     | 
    
         
             
                  :PUBLIC_LINK_PATHS,
         
     | 
| 
       56 
55 
     | 
    
         
             
                  :JWT_AUDIENCE,
         
     | 
| 
         @@ -71,10 +70,9 @@ module Aspera 
     | 
|
| 
       71 
70 
     | 
    
         
             
                # class static methods
         
     | 
| 
       72 
71 
     | 
    
         
             
                class << self
         
     | 
| 
       73 
72 
     | 
    
         
             
                  # strings /Applications/Aspera\ Drive.app/Contents/MacOS/AsperaDrive|grep -E '.{100}==$'|base64 --decode
         
     | 
| 
       74 
     | 
    
         
            -
                  def get_client_info(client_name= 
     | 
| 
       75 
     | 
    
         
            -
                     
     | 
| 
       76 
     | 
    
         
            -
                     
     | 
| 
       77 
     | 
    
         
            -
                    return client_name, Base64.urlsafe_encode64(DataRepository.instance.data(DATA_REPO_INDEX_START + client_index))
         
     | 
| 
      
 73 
     | 
    
         
            +
                  def get_client_info(client_name=nil)
         
     | 
| 
      
 74 
     | 
    
         
            +
                    client_key = client_name.nil? ? GLOBAL_CLIENT_APPS.first : client_name.to_sym
         
     | 
| 
      
 75 
     | 
    
         
            +
                    return client_key, DataRepository.instance.item(client_key)
         
     | 
| 
       78 
76 
     | 
    
         
             
                  end
         
     | 
| 
       79 
77 
     | 
    
         | 
| 
       80 
78 
     | 
    
         
             
                  # base API url depends on domain, which could be "qa.xxx"
         
     | 
| 
         @@ -93,7 +91,7 @@ module Aspera 
     | 
|
| 
       93 
91 
     | 
    
         
             
                  def url_parts(uri)
         
     | 
| 
       94 
92 
     | 
    
         
             
                    raise "No host found in URL.Please check URL format: https://myorg.#{PROD_DOMAIN}" if uri.host.nil?
         
     | 
| 
       95 
93 
     | 
    
         
             
                    parts = uri.host.split('.', 2)
         
     | 
| 
       96 
     | 
    
         
            -
                     
     | 
| 
      
 94 
     | 
    
         
            +
                    assert(parts.length == 2){"expecting a public FQDN for #{PRODUCT_NAME}"}
         
     | 
| 
       97 
95 
     | 
    
         
             
                    return parts
         
     | 
| 
       98 
96 
     | 
    
         
             
                  end
         
     | 
| 
       99 
97 
     | 
    
         | 
| 
         @@ -161,6 +159,7 @@ module Aspera 
     | 
|
| 
       161 
159 
     | 
    
         
             
                  @workspace_name = workspace
         
     | 
| 
       162 
160 
     | 
    
         
             
                  @cache_user_info = nil
         
     | 
| 
       163 
161 
     | 
    
         
             
                  @cache_url_token_info = nil
         
     | 
| 
      
 162 
     | 
    
         
            +
                  @context_cache = nil
         
     | 
| 
       164 
163 
     | 
    
         
             
                  # init rest params
         
     | 
| 
       165 
164 
     | 
    
         
             
                  aoc_rest_p = {auth: {type: :oauth2}}
         
     | 
| 
       166 
165 
     | 
    
         
             
                  # shortcut to auth section
         
     | 
| 
         @@ -212,7 +211,7 @@ module Aspera 
     | 
|
| 
       212 
211 
     | 
    
         
             
                    aoc_auth_p[:aoc_pub_link][:json][:password] = password unless password.nil?
         
     | 
| 
       213 
212 
     | 
    
         
             
                    # basic auth required for /token
         
     | 
| 
       214 
213 
     | 
    
         
             
                    aoc_auth_p[:auth] = {type: :basic, username: aoc_auth_p[:client_id], password: aoc_auth_p[:client_secret]}
         
     | 
| 
       215 
     | 
    
         
            -
                  else  
     | 
| 
      
 214 
     | 
    
         
            +
                  else error_unexpected_value(aoc_auth_p[:grant_method])
         
     | 
| 
       216 
215 
     | 
    
         
             
                  end
         
     | 
| 
       217 
216 
     | 
    
         
             
                  super(aoc_rest_p)
         
     | 
| 
       218 
217 
     | 
    
         
             
                end
         
     | 
| 
         @@ -226,7 +225,7 @@ module Aspera 
     | 
|
| 
       226 
225 
     | 
    
         
             
                end
         
     | 
| 
       227 
226 
     | 
    
         | 
| 
       228 
227 
     | 
    
         
             
                def assert_public_link_types(expected)
         
     | 
| 
       229 
     | 
    
         
            -
                   
     | 
| 
      
 228 
     | 
    
         
            +
                  assert_values(public_link['purpose'], expected){'public link type'}
         
     | 
| 
       230 
229 
     | 
    
         
             
                end
         
     | 
| 
       231 
230 
     | 
    
         | 
| 
       232 
231 
     | 
    
         
             
                def additional_persistence_ids
         
     | 
| 
         @@ -234,12 +233,6 @@ module Aspera 
     | 
|
| 
       234 
233 
     | 
    
         
             
                  return [] # TODO : public_link['id'] ?
         
     | 
| 
       235 
234 
     | 
    
         
             
                end
         
     | 
| 
       236 
235 
     | 
    
         | 
| 
       237 
     | 
    
         
            -
                # def secret_finder=(secret_finder)
         
     | 
| 
       238 
     | 
    
         
            -
                #  raise 'secret finder already set' unless @secret_finder.nil?
         
     | 
| 
       239 
     | 
    
         
            -
                #  raise 'secret finder must have lookup_secret' unless secret_finder.respond_to?(:lookup_secret)
         
     | 
| 
       240 
     | 
    
         
            -
                #  @secret_finder = secret_finder
         
     | 
| 
       241 
     | 
    
         
            -
                # end
         
     | 
| 
       242 
     | 
    
         
            -
             
     | 
| 
       243 
236 
     | 
    
         
             
                # cached user information
         
     | 
| 
       244 
237 
     | 
    
         
             
                def current_user_info(exception: false)
         
     | 
| 
       245 
238 
     | 
    
         
             
                  return @cache_user_info unless @cache_user_info.nil?
         
     | 
| 
         @@ -252,7 +245,7 @@ module Aspera 
     | 
|
| 
       252 
245 
     | 
    
         
             
                      Log.log.debug{"ignoring error: #{e}"}
         
     | 
| 
       253 
246 
     | 
    
         
             
                      {}
         
     | 
| 
       254 
247 
     | 
    
         
             
                    end
         
     | 
| 
       255 
     | 
    
         
            -
                  USER_INFO_FIELDS_MIN.each{|f|@cache_user_info[f] =  
     | 
| 
      
 248 
     | 
    
         
            +
                  USER_INFO_FIELDS_MIN.each{|f|@cache_user_info[f] = nil if @cache_user_info[f].nil?}
         
     | 
| 
       256 
249 
     | 
    
         
             
                  return @cache_user_info
         
     | 
| 
       257 
250 
     | 
    
         
             
                end
         
     | 
| 
       258 
251 
     | 
    
         | 
| 
         @@ -260,7 +253,8 @@ module Aspera 
     | 
|
| 
       260 
253 
     | 
    
         
             
                # @return [Hash] current context information: workspace, and home node/file if app is "Files"
         
     | 
| 
       261 
254 
     | 
    
         
             
                def context(application = nil)
         
     | 
| 
       262 
255 
     | 
    
         
             
                  return @context_cache unless @context_cache.nil?
         
     | 
| 
       263 
     | 
    
         
            -
                   
     | 
| 
      
 256 
     | 
    
         
            +
                  assert(!application.nil?){'application must be set once'}
         
     | 
| 
      
 257 
     | 
    
         
            +
                  assert_values(application, %i[files packages])
         
     | 
| 
       264 
258 
     | 
    
         
             
                  ws_id =
         
     | 
| 
       265 
259 
     | 
    
         
             
                    if !public_link.nil?
         
     | 
| 
       266 
260 
     | 
    
         
             
                      Log.log.debug('Using workspace of public link')
         
     | 
| 
         @@ -323,7 +317,7 @@ module Aspera 
     | 
|
| 
       323 
317 
     | 
    
         
             
                # @param package_info [Hash] created package information
         
     | 
| 
       324 
318 
     | 
    
         
             
                # @returns [Aspera::Node] a node API for access key
         
     | 
| 
       325 
319 
     | 
    
         
             
                def node_api_from(node_id:, workspace_id: nil, workspace_name: nil, scope: Aspera::Node::SCOPE_USER, package_info: nil)
         
     | 
| 
       326 
     | 
    
         
            -
                   
     | 
| 
      
 320 
     | 
    
         
            +
                  assert_type(node_id, String)
         
     | 
| 
       327 
321 
     | 
    
         
             
                  node_info = read("nodes/#{node_id}")[:data]
         
     | 
| 
       328 
322 
     | 
    
         
             
                  if workspace_name.nil? && !workspace_id.nil?
         
     | 
| 
       329 
323 
     | 
    
         
             
                    workspace_name = read("workspaces/#{workspace_id}")[:data]['name']
         
     | 
| 
         @@ -370,16 +364,16 @@ module Aspera 
     | 
|
| 
       370 
364 
     | 
    
         
             
                    Log.log.debug('no metadata in shared inbox')
         
     | 
| 
       371 
365 
     | 
    
         
             
                    return
         
     | 
| 
       372 
366 
     | 
    
         
             
                  end
         
     | 
| 
      
 367 
     | 
    
         
            +
                  assert(pkg_data.key?('metadata')){"package requires metadata: #{meta_schema}"}
         
     | 
| 
       373 
368 
     | 
    
         
             
                  pkg_meta = pkg_data['metadata']
         
     | 
| 
       374 
     | 
    
         
            -
                   
     | 
| 
       375 
     | 
    
         
            -
                  raise 'metadata must be an Array' unless pkg_meta.is_a?(Array)
         
     | 
| 
      
 369 
     | 
    
         
            +
                  assert_type(pkg_meta, Array){'metadata'}
         
     | 
| 
       376 
370 
     | 
    
         
             
                  Log.log.debug{Log.dump(:metadata, pkg_meta)}
         
     | 
| 
       377 
371 
     | 
    
         
             
                  pkg_meta.each do |field|
         
     | 
| 
       378 
     | 
    
         
            -
                     
     | 
| 
       379 
     | 
    
         
            -
                     
     | 
| 
       380 
     | 
    
         
            -
                     
     | 
| 
       381 
     | 
    
         
            -
                     
     | 
| 
       382 
     | 
    
         
            -
                     
     | 
| 
      
 372 
     | 
    
         
            +
                    assert_type(field, Hash){'metadata field'}
         
     | 
| 
      
 373 
     | 
    
         
            +
                    assert(field.key?('name')){'metadata field must have name'}
         
     | 
| 
      
 374 
     | 
    
         
            +
                    assert(field.key?('values')){'metadata field must have values'}
         
     | 
| 
      
 375 
     | 
    
         
            +
                    assert_type(field['values'], Array){'metadata field values'}
         
     | 
| 
      
 376 
     | 
    
         
            +
                    assert(!meta_schema.select{|i|i['name'].eql?(field['name'])}.empty?){"unknown metadata field: #{field['name']}"}
         
     | 
| 
       383 
377 
     | 
    
         
             
                  end
         
     | 
| 
       384 
378 
     | 
    
         
             
                  meta_schema.each do |field|
         
     | 
| 
       385 
379 
     | 
    
         
             
                    provided = pkg_meta.select{|i|i['name'].eql?(field['name'])}
         
     | 
| 
         @@ -396,15 +390,15 @@ module Aspera 
     | 
|
| 
       396 
390 
     | 
    
         
             
                # @return nil package_data is modified
         
     | 
| 
       397 
391 
     | 
    
         
             
                def resolve_package_recipients(package_data, ws_id, recipient_list_field, new_user_option)
         
     | 
| 
       398 
392 
     | 
    
         
             
                  return unless package_data.key?(recipient_list_field)
         
     | 
| 
       399 
     | 
    
         
            -
                   
     | 
| 
      
 393 
     | 
    
         
            +
                  assert_type(package_data[recipient_list_field], Array){recipient_list_field}
         
     | 
| 
       400 
394 
     | 
    
         
             
                  new_user_option = {'package_contact' => true} if new_user_option.nil?
         
     | 
| 
       401 
     | 
    
         
            -
                   
     | 
| 
      
 395 
     | 
    
         
            +
                  assert_type(new_user_option, Hash){'new_user_option'}
         
     | 
| 
       402 
396 
     | 
    
         
             
                  # list with resolved elements
         
     | 
| 
       403 
397 
     | 
    
         
             
                  resolved_list = []
         
     | 
| 
       404 
398 
     | 
    
         
             
                  package_data[recipient_list_field].each do |short_recipient_info|
         
     | 
| 
       405 
399 
     | 
    
         
             
                    case short_recipient_info
         
     | 
| 
       406 
400 
     | 
    
         
             
                    when Hash # native API information, check keys
         
     | 
| 
       407 
     | 
    
         
            -
                       
     | 
| 
      
 401 
     | 
    
         
            +
                      assert(short_recipient_info.keys.sort.eql?(%w[id type])){"#{recipient_list_field} element shall have fields: id and type"}
         
     | 
| 
       408 
402 
     | 
    
         
             
                    when String # CLI helper: need to resolve provided name to type/id
         
     | 
| 
       409 
403 
     | 
    
         
             
                      # email: user, else dropbox
         
     | 
| 
       410 
404 
     | 
    
         
             
                      entity_type = short_recipient_info.include?('@') ? 'contacts' : 'dropboxes'
         
     | 
| 
         @@ -450,7 +444,7 @@ module Aspera 
     | 
|
| 
       450 
444 
     | 
    
         
             
                      })
         
     | 
| 
       451 
445 
     | 
    
         
             
                    end
         
     | 
| 
       452 
446 
     | 
    
         
             
                    pkg_data['metadata'] = api_meta
         
     | 
| 
       453 
     | 
    
         
            -
                  else  
     | 
| 
      
 447 
     | 
    
         
            +
                  else error_unexpected_value(pkg_meta.class)
         
     | 
| 
       454 
448 
     | 
    
         
             
                  end
         
     | 
| 
       455 
449 
     | 
    
         
             
                  return nil
         
     | 
| 
       456 
450 
     | 
    
         
             
                end
         
     | 
| 
         @@ -513,7 +507,7 @@ module Aspera 
     | 
|
| 
       513 
507 
     | 
    
         
             
                  # Console cookie
         
     | 
| 
       514 
508 
     | 
    
         
             
                  ################
         
     | 
| 
       515 
509 
     | 
    
         
             
                  # we are sure that fields are not nil
         
     | 
| 
       516 
     | 
    
         
            -
                  cookie_elements = [app_info[:app], current_user_info['name'], current_user_info['email']].map{|e|Base64.strict_encode64(e)}
         
     | 
| 
      
 510 
     | 
    
         
            +
                  cookie_elements = [app_info[:app], current_user_info['name'] || 'public link', current_user_info['email'] || 'none'].map{|e|Base64.strict_encode64(e)}
         
     | 
| 
       517 
511 
     | 
    
         
             
                  cookie_elements.unshift(COOKIE_PREFIX_CONSOLE_AOC)
         
     | 
| 
       518 
512 
     | 
    
         
             
                  transfer_spec['cookie'] = cookie_elements.join(':')
         
     | 
| 
       519 
513 
     | 
    
         
             
                  # Application tags
         
     | 
| 
         @@ -590,7 +584,8 @@ module Aspera 
     | 
|
| 
       590 
584 
     | 
    
         
             
                # @param app_info [Hash] hash with app info
         
     | 
| 
       591 
585 
     | 
    
         
             
                # @param types [Array] event types
         
     | 
| 
       592 
586 
     | 
    
         
             
                def permissions_send_event(created_data:, app_info:, types: PERMISSIONS_CREATED)
         
     | 
| 
       593 
     | 
    
         
            -
                   
     | 
| 
      
 587 
     | 
    
         
            +
                  assert_type(types, Array)
         
     | 
| 
      
 588 
     | 
    
         
            +
                  assert(!types.empty?)
         
     | 
| 
       594 
589 
     | 
    
         
             
                  event_creation = {
         
     | 
| 
       595 
590 
     | 
    
         
             
                    'types'        => types,
         
     | 
| 
       596 
591 
     | 
    
         
             
                    'node_id'      => app_info[:node_info]['id'],
         
     | 
    
        data/lib/aspera/ascmd.rb
    CHANGED
    
    | 
         @@ -2,6 +2,7 @@ 
     | 
|
| 
       2 
2 
     | 
    
         | 
| 
       3 
3 
     | 
    
         
             
            # cspell:ignore ascmd smode errstr zstr zmode zuid zgid zctime zatime zmtime fcount dcount btype blist codeset lc_ctype ascmdtypes
         
     | 
| 
       4 
4 
     | 
    
         
             
            require 'aspera/log'
         
     | 
| 
      
 5 
     | 
    
         
            +
            require 'aspera/assert'
         
     | 
| 
       5 
6 
     | 
    
         | 
| 
       6 
7 
     | 
    
         
             
            module Aspera
         
     | 
| 
       7 
8 
     | 
    
         
             
              # Run +ascmd+ commands using specified executor (usually, remotely on transfer node)
         
     | 
| 
         @@ -52,7 +53,7 @@ module Aspera 
     | 
|
| 
       52 
53 
     | 
    
         
             
                    end
         
     | 
| 
       53 
54 
     | 
    
         
             
                  end
         
     | 
| 
       54 
55 
     | 
    
         
             
                  # for info, second overrides first, so restore it
         
     | 
| 
       55 
     | 
    
         
            -
                  case result.keys.length; when 0 then result = system_info; when 1 then result = result[result.keys.first]; else  
     | 
| 
      
 56 
     | 
    
         
            +
                  case result.keys.length; when 0 then result = system_info; when 1 then result = result[result.keys.first]; else error_unexpected_value(result.keys.length); end
         
     | 
| 
       56 
57 
     | 
    
         
             
                  # raise error as exception
         
     | 
| 
       57 
58 
     | 
    
         
             
                  raise Error.new(result[:errno], result[:errstr], action_sym, arguments) if
         
     | 
| 
       58 
59 
     | 
    
         
             
                    result.is_a?(Hash) && (result.keys.sort == TYPES_DESCR[:error][:fields].map{|i|i[:name]}.sort)
         
     | 
| 
         @@ -65,10 +66,6 @@ module Aspera 
     | 
|
| 
       65 
66 
     | 
    
         
             
                    super(); @errno = errno; @errstr = errstr; @command = cmd; @arguments = arguments; end # rubocop:disable Style/Semicolon
         
     | 
| 
       66 
67 
     | 
    
         | 
| 
       67 
68 
     | 
    
         
             
                  def message; "ascmd: #{@errstr} (#{@errno})"; end
         
     | 
| 
       68 
     | 
    
         
            -
             
     | 
| 
       69 
     | 
    
         
            -
                  # TODO : delete : attr_reader :errno #, :errstr, :command
         
     | 
| 
       70 
     | 
    
         
            -
                  # TODO : delete :def args; @arguments; end
         
     | 
| 
       71 
     | 
    
         
            -
             
     | 
| 
       72 
69 
     | 
    
         
             
                  def extended_message; "ascmd: errno=#{@errno} errstr=\"#{@errstr}\" command=#{@command} arguments=#{@arguments.join(',')}"; end
         
     | 
| 
       73 
70 
     | 
    
         
             
                end # Error
         
     | 
| 
       74 
71 
     | 
    
         | 
| 
         @@ -177,7 +174,7 @@ module Aspera 
     | 
|
| 
       177 
174 
     | 
    
         
             
                          end
         
     | 
| 
       178 
175 
     | 
    
         
             
                        end
         
     | 
| 
       179 
176 
     | 
    
         
             
                      end
         
     | 
| 
       180 
     | 
    
         
            -
                    else  
     | 
| 
      
 177 
     | 
    
         
            +
                    else error_unexpected_value(type_descr[:decode])
         
     | 
| 
       181 
178 
     | 
    
         
             
                    end # is_a
         
     | 
| 
       182 
179 
     | 
    
         
             
                    return result
         
     | 
| 
       183 
180 
     | 
    
         
             
                  end
         
     | 
| 
         @@ -0,0 +1,45 @@ 
     | 
|
| 
      
 1 
     | 
    
         
            +
            # frozen_string_literal: true
         
     | 
| 
      
 2 
     | 
    
         
            +
             
     | 
| 
      
 3 
     | 
    
         
            +
            module Aspera
         
     | 
| 
      
 4 
     | 
    
         
            +
              class InternalError < StandardError
         
     | 
| 
      
 5 
     | 
    
         
            +
              end
         
     | 
| 
      
 6 
     | 
    
         
            +
             
     | 
| 
      
 7 
     | 
    
         
            +
              class AssertError < StandardError
         
     | 
| 
      
 8 
     | 
    
         
            +
              end
         
     | 
| 
      
 9 
     | 
    
         
            +
            end
         
     | 
| 
      
 10 
     | 
    
         
            +
             
     | 
| 
      
 11 
     | 
    
         
            +
            class Object
         
     | 
| 
      
 12 
     | 
    
         
            +
              def assert(assertion, info = nil, level: 2, exception_class: Aspera::AssertError)
         
     | 
| 
      
 13 
     | 
    
         
            +
                raise Aspera::InternalError, 'bad assert: both info and block given' unless info.nil? || !block_given?
         
     | 
| 
      
 14 
     | 
    
         
            +
                return if assertion
         
     | 
| 
      
 15 
     | 
    
         
            +
                message = 'assertion failed'
         
     | 
| 
      
 16 
     | 
    
         
            +
                info = yield if block_given?
         
     | 
| 
      
 17 
     | 
    
         
            +
                message = "#{message}: #{info}" if info
         
     | 
| 
      
 18 
     | 
    
         
            +
                message = "#{message}: #{caller(level..level).first}"
         
     | 
| 
      
 19 
     | 
    
         
            +
                raise exception_class, message
         
     | 
| 
      
 20 
     | 
    
         
            +
              end
         
     | 
| 
      
 21 
     | 
    
         
            +
             
     | 
| 
      
 22 
     | 
    
         
            +
              # assert that value has the given type
         
     | 
| 
      
 23 
     | 
    
         
            +
              # @param value [Object] the value to check
         
     | 
| 
      
 24 
     | 
    
         
            +
              # @param type [Class] the expected type
         
     | 
| 
      
 25 
     | 
    
         
            +
              def assert_type(value, type, exception_class: Aspera::AssertError)
         
     | 
| 
      
 26 
     | 
    
         
            +
                assert(value.is_a?(type), level: 3, exception_class: exception_class){"#{block_given? ? "#{yield}: " : nil}expecting #{type}, but have #{value.inspect}"}
         
     | 
| 
      
 27 
     | 
    
         
            +
              end
         
     | 
| 
      
 28 
     | 
    
         
            +
             
     | 
| 
      
 29 
     | 
    
         
            +
              # assert that value is one of the given values
         
     | 
| 
      
 30 
     | 
    
         
            +
              def assert_values(value, values, exception_class: Aspera::AssertError)
         
     | 
| 
      
 31 
     | 
    
         
            +
                assert(values.include?(value), level: 3, exception_class: exception_class) do
         
     | 
| 
      
 32 
     | 
    
         
            +
                  "#{block_given? ? "#{yield}: " : nil}expecting one of #{values.inspect}, but have #{value.inspect}"
         
     | 
| 
      
 33 
     | 
    
         
            +
                end
         
     | 
| 
      
 34 
     | 
    
         
            +
              end
         
     | 
| 
      
 35 
     | 
    
         
            +
             
     | 
| 
      
 36 
     | 
    
         
            +
              # the line with this shall never be reached
         
     | 
| 
      
 37 
     | 
    
         
            +
              def error_unreachable_line
         
     | 
| 
      
 38 
     | 
    
         
            +
                raise Aspera::InternalError, "unreachable line reached: #{caller(2..2).first}"
         
     | 
| 
      
 39 
     | 
    
         
            +
              end
         
     | 
| 
      
 40 
     | 
    
         
            +
             
     | 
| 
      
 41 
     | 
    
         
            +
              # the value is not one of the expected values
         
     | 
| 
      
 42 
     | 
    
         
            +
              def error_unexpected_value(value, exception_class: Aspera::InternalError)
         
     | 
| 
      
 43 
     | 
    
         
            +
                raise exception_class, "#{block_given? ? "#{yield}: " : nil}unexpected value: #{value.inspect}"
         
     | 
| 
      
 44 
     | 
    
         
            +
              end
         
     | 
| 
      
 45 
     | 
    
         
            +
            end
         
     | 
| 
         @@ -4,6 +4,7 @@ 
     | 
|
| 
       4 
4 
     | 
    
         
             
            require 'aspera/uri_reader'
         
     | 
| 
       5 
5 
     | 
    
         
             
            require 'aspera/environment'
         
     | 
| 
       6 
6 
     | 
    
         
             
            require 'aspera/log'
         
     | 
| 
      
 7 
     | 
    
         
            +
            require 'aspera/assert'
         
     | 
| 
       7 
8 
     | 
    
         
             
            require 'json'
         
     | 
| 
       8 
9 
     | 
    
         
             
            require 'base64'
         
     | 
| 
       9 
10 
     | 
    
         
             
            require 'zlib'
         
     | 
| 
         @@ -17,6 +18,7 @@ module Aspera 
     | 
|
| 
       17 
18 
     | 
    
         
             
                  include Singleton
         
     | 
| 
       18 
19 
     | 
    
         | 
| 
       19 
20 
     | 
    
         
             
                  # special values
         
     | 
| 
      
 21 
     | 
    
         
            +
                  INIT = 'INIT'
         
     | 
| 
       20 
22 
     | 
    
         
             
                  ALL = 'ALL'
         
     | 
| 
       21 
23 
     | 
    
         
             
                  DEF = 'DEF'
         
     | 
| 
       22 
24 
     | 
    
         | 
| 
         @@ -30,9 +32,7 @@ module Aspera 
     | 
|
| 
       30 
32 
     | 
    
         
             
                        if col_titles.nil?
         
     | 
| 
       31 
33 
     | 
    
         
             
                          col_titles = values
         
     | 
| 
       32 
34 
     | 
    
         
             
                        else
         
     | 
| 
       33 
     | 
    
         
            -
                           
     | 
| 
       34 
     | 
    
         
            -
                          col_titles.each{|title|entry[title] = values.shift}
         
     | 
| 
       35 
     | 
    
         
            -
                          hash_array.push(entry)
         
     | 
| 
      
 35 
     | 
    
         
            +
                          hash_array.push(col_titles.zip(values).to_h)
         
     | 
| 
       36 
36 
     | 
    
         
             
                        end
         
     | 
| 
       37 
37 
     | 
    
         
             
                      end
         
     | 
| 
       38 
38 
     | 
    
         
             
                      Log.log.warn('Titled CSV file without any line') if hash_array.empty?
         
     | 
| 
         @@ -63,7 +63,7 @@ module Aspera 
     | 
|
| 
       63 
63 
     | 
    
         
             
                      path:   lambda{|v|File.expand_path(v)},
         
     | 
| 
       64 
64 
     | 
    
         
             
                      re:     lambda{|v|Regexp.new(v)},
         
     | 
| 
       65 
65 
     | 
    
         
             
                      ruby:   lambda{|v|Environment.secure_eval(v, __FILE__, __LINE__)},
         
     | 
| 
       66 
     | 
    
         
            -
                      secret: lambda{|v| 
     | 
| 
      
 66 
     | 
    
         
            +
                      secret: lambda{|v|prompt = v.empty? ? 'secret' : v; $stdin.getpass("#{prompt}> ")}, # rubocop:disable Style/Semicolon
         
     | 
| 
       67 
67 
     | 
    
         
             
                      stdin:  lambda{|v|ExtendedValue.assert_no_value(v, :stdin); $stdin.read}, # rubocop:disable Style/Semicolon
         
     | 
| 
       68 
68 
     | 
    
         
             
                      yaml:   lambda{|v|YAML.load(v)},
         
     | 
| 
       69 
69 
     | 
    
         
             
                      zlib:   lambda{|v|Zlib::Inflate.inflate(v)},
         
     | 
| 
         @@ -78,7 +78,7 @@ module Aspera 
     | 
|
| 
       78 
78 
     | 
    
         
             
                  # add a new handler
         
     | 
| 
       79 
79 
     | 
    
         
             
                  def set_handler(name, method)
         
     | 
| 
       80 
80 
     | 
    
         
             
                    Log.log.debug{"setting handler for #{name}"}
         
     | 
| 
       81 
     | 
    
         
            -
                     
     | 
| 
      
 81 
     | 
    
         
            +
                    assert_type(name, Symbol){'name'}
         
     | 
| 
       82 
82 
     | 
    
         
             
                    @handlers[name] = method
         
     | 
| 
       83 
83 
     | 
    
         
             
                  end
         
     | 
| 
       84 
84 
     | 
    
         | 
    
        data/lib/aspera/cli/formatter.rb
    CHANGED
    
    | 
         @@ -3,6 +3,8 @@ 
     | 
|
| 
       3 
3 
     | 
    
         
             
            # cspell:ignore jsonpp
         
     | 
| 
       4 
4 
     | 
    
         
             
            require 'aspera/secret_hider'
         
     | 
| 
       5 
5 
     | 
    
         
             
            require 'aspera/environment'
         
     | 
| 
      
 6 
     | 
    
         
            +
            require 'aspera/log'
         
     | 
| 
      
 7 
     | 
    
         
            +
            require 'aspera/assert'
         
     | 
| 
       6 
8 
     | 
    
         
             
            require 'terminal-table'
         
     | 
| 
       7 
9 
     | 
    
         
             
            require 'yaml'
         
     | 
| 
       8 
10 
     | 
    
         
             
            require 'pp'
         
     | 
| 
         @@ -18,7 +20,7 @@ module Aspera 
     | 
|
| 
       18 
20 
     | 
    
         | 
| 
       19 
21 
     | 
    
         
             
                  # General method
         
     | 
| 
       20 
22 
     | 
    
         
             
                  def flatten(something)
         
     | 
| 
       21 
     | 
    
         
            -
                     
     | 
| 
      
 23 
     | 
    
         
            +
                    assert_type(something, Hash)
         
     | 
| 
       22 
24 
     | 
    
         
             
                    @result = {}
         
     | 
| 
       23 
25 
     | 
    
         
             
                    flatten_any(something, '')
         
     | 
| 
       24 
26 
     | 
    
         
             
                    return @result
         
     | 
| 
         @@ -94,6 +96,7 @@ module Aspera 
     | 
|
| 
       94 
96 
     | 
    
         
             
                  DISPLAY_FORMATS = %i[text nagios ruby json jsonpp yaml table csv].freeze
         
     | 
| 
       95 
97 
     | 
    
         
             
                  # user output levels
         
     | 
| 
       96 
98 
     | 
    
         
             
                  DISPLAY_LEVELS = %i[info data error].freeze
         
     | 
| 
      
 99 
     | 
    
         
            +
                  RESULT_PARAMS = %i[type data total fields name].freeze
         
     | 
| 
       97 
100 
     | 
    
         | 
| 
       98 
101 
     | 
    
         
             
                  private_constant :DISPLAY_FORMATS, :DISPLAY_LEVELS, :CSV_RECORD_SEPARATOR, :CSV_FIELD_SEPARATOR
         
     | 
| 
       99 
102 
     | 
    
         
             
                  # prefix to display error messages in user messages (terminal)
         
     | 
| 
         @@ -155,16 +158,26 @@ module Aspera 
     | 
|
| 
       155 
158 
     | 
    
         
             
                  end
         
     | 
| 
       156 
159 
     | 
    
         | 
| 
       157 
160 
     | 
    
         
             
                  def option_handler(option_symbol, operation, value=nil)
         
     | 
| 
      
 161 
     | 
    
         
            +
                    assert_values(operation, %i[set get])
         
     | 
| 
       158 
162 
     | 
    
         
             
                    case operation
         
     | 
| 
       159 
     | 
    
         
            -
                    when :set 
     | 
| 
      
 163 
     | 
    
         
            +
                    when :set
         
     | 
| 
      
 164 
     | 
    
         
            +
                      @options[option_symbol] = value
         
     | 
| 
      
 165 
     | 
    
         
            +
                      if option_symbol.eql?(:output)
         
     | 
| 
      
 166 
     | 
    
         
            +
                        $stdout = if value.eql?('-')
         
     | 
| 
      
 167 
     | 
    
         
            +
                          STDOUT # rubocop:disable Style/GlobalStdStream
         
     | 
| 
      
 168 
     | 
    
         
            +
                        else
         
     | 
| 
      
 169 
     | 
    
         
            +
                          File.open(value, 'w')
         
     | 
| 
      
 170 
     | 
    
         
            +
                        end
         
     | 
| 
      
 171 
     | 
    
         
            +
                      end
         
     | 
| 
       160 
172 
     | 
    
         
             
                    when :get then return @options[option_symbol]
         
     | 
| 
       161 
     | 
    
         
            -
                    else  
     | 
| 
      
 173 
     | 
    
         
            +
                    else error_unreachable_line
         
     | 
| 
       162 
174 
     | 
    
         
             
                    end
         
     | 
| 
       163 
175 
     | 
    
         
             
                    nil
         
     | 
| 
       164 
176 
     | 
    
         
             
                  end
         
     | 
| 
       165 
177 
     | 
    
         | 
| 
       166 
178 
     | 
    
         
             
                  def declare_options(options)
         
     | 
| 
       167 
179 
     | 
    
         
             
                    options.declare(:format, 'Output format', values: DISPLAY_FORMATS, handler: {o: self, m: :option_handler}, default: :table)
         
     | 
| 
      
 180 
     | 
    
         
            +
                    options.declare(:output, 'Destination for results', types: String, handler: {o: self, m: :option_handler})
         
     | 
| 
       168 
181 
     | 
    
         
             
                    options.declare(:display, 'Output only some information', values: DISPLAY_LEVELS, handler: {o: self, m: :option_handler}, default: :info)
         
     | 
| 
       169 
182 
     | 
    
         
             
                    options.declare(
         
     | 
| 
       170 
183 
     | 
    
         
             
                      :fields, "Comma separated list of: fields, or #{ExtendedValue::ALL}, or #{ExtendedValue::DEF}", handler: {o: self, m: :option_handler},
         
     | 
| 
         @@ -186,7 +199,7 @@ module Aspera 
     | 
|
| 
       186 
199 
     | 
    
         
             
                    when :data then $stdout.puts(message) unless @options[:display].eql?(:error)
         
     | 
| 
       187 
200 
     | 
    
         
             
                    when :info then $stdout.puts(message) if @options[:display].eql?(:info)
         
     | 
| 
       188 
201 
     | 
    
         
             
                    when :error then $stderr.puts(message)
         
     | 
| 
       189 
     | 
    
         
            -
                    else  
     | 
| 
      
 202 
     | 
    
         
            +
                    else error_unexpected_value(message_level)
         
     | 
| 
       190 
203 
     | 
    
         
             
                    end
         
     | 
| 
       191 
204 
     | 
    
         
             
                  end
         
     | 
| 
       192 
205 
     | 
    
         | 
| 
         @@ -219,7 +232,7 @@ module Aspera 
     | 
|
| 
       219 
232 
     | 
    
         
             
                      when Array then @options[:fields]
         
     | 
| 
       220 
233 
     | 
    
         
             
                      when Regexp then return all_fields(data).select{|i|i.match(@options[:fields])}
         
     | 
| 
       221 
234 
     | 
    
         
             
                      when Proc then return all_fields(data).select{|i|@options[:fields].call(i)}
         
     | 
| 
       222 
     | 
    
         
            -
                      else  
     | 
| 
      
 235 
     | 
    
         
            +
                      else error_unexpected_value(@options[:fields])
         
     | 
| 
       223 
236 
     | 
    
         
             
                      end
         
     | 
| 
       224 
237 
     | 
    
         
             
                    result = []
         
     | 
| 
       225 
238 
     | 
    
         
             
                    until request.empty?
         
     | 
| 
         @@ -252,7 +265,7 @@ module Aspera 
     | 
|
| 
       252 
265 
     | 
    
         
             
                  # object_array: array of hash
         
     | 
| 
       253 
266 
     | 
    
         
             
                  # fields: list of column names
         
     | 
| 
       254 
267 
     | 
    
         
             
                  def display_table(object_array, fields)
         
     | 
| 
       255 
     | 
    
         
            -
                     
     | 
| 
      
 268 
     | 
    
         
            +
                    assert(!fields.nil?){'missing fields parameter'}
         
     | 
| 
       256 
269 
     | 
    
         
             
                    case @options[:select]
         
     | 
| 
       257 
270 
     | 
    
         
             
                    when Proc
         
     | 
| 
       258 
271 
     | 
    
         
             
                      object_array.select!{|i|@options[:select].call(i)}
         
     | 
| 
         @@ -296,12 +309,12 @@ module Aspera 
     | 
|
| 
       296 
309 
     | 
    
         | 
| 
       297 
310 
     | 
    
         
             
                  # this method displays the results, especially the table format
         
     | 
| 
       298 
311 
     | 
    
         
             
                  def display_results(results)
         
     | 
| 
       299 
     | 
    
         
            -
                     
     | 
| 
       300 
     | 
    
         
            -
                     
     | 
| 
       301 
     | 
    
         
            -
                     
     | 
| 
       302 
     | 
    
         
            -
                     
     | 
| 
       303 
     | 
    
         
            -
                    raise 'INTERNAL ERROR, result must have data' unless results.key?(:data) || %i[empty nothing].include?(results[:type])
         
     | 
| 
      
 312 
     | 
    
         
            +
                    assert_type(results, Hash)
         
     | 
| 
      
 313 
     | 
    
         
            +
                    assert((results.keys - RESULT_PARAMS).empty?){"result unsupported key: #{results.keys - RESULT_PARAMS}"}
         
     | 
| 
      
 314 
     | 
    
         
            +
                    assert(results.key?(:type)){"result must have type (#{results})"}
         
     | 
| 
      
 315 
     | 
    
         
            +
                    assert(results.key?(:data) || %i[empty nothing].include?(results[:type])){'result must have data'}
         
     | 
| 
       304 
316 
     | 
    
         
             
                    Log.log.debug{"display_results: #{results[:data].class} #{results[:type]}"}
         
     | 
| 
      
 317 
     | 
    
         
            +
                    display_item_count(results[:data].length, results[:total]) if results.key?(:total)
         
     | 
| 
       305 
318 
     | 
    
         
             
                    SecretHider.deep_remove_secret(results[:data]) unless @options[:show_secrets] || @options[:display].eql?(:data)
         
     | 
| 
       306 
319 
     | 
    
         
             
                    case @options[:format]
         
     | 
| 
       307 
320 
     | 
    
         
             
                    when :text
         
     | 
| 
         @@ -323,8 +336,8 @@ module Aspera 
     | 
|
| 
       323 
336 
     | 
    
         
             
                      when :object_list, :single_object
         
     | 
| 
       324 
337 
     | 
    
         
             
                        obj_list = results[:data]
         
     | 
| 
       325 
338 
     | 
    
         
             
                        obj_list = [obj_list] if results[:type].eql?(:single_object)
         
     | 
| 
       326 
     | 
    
         
            -
                         
     | 
| 
       327 
     | 
    
         
            -
                         
     | 
| 
      
 339 
     | 
    
         
            +
                        assert_type(obj_list, Array)
         
     | 
| 
      
 340 
     | 
    
         
            +
                        assert(obj_list.all?(Hash)){"expecting Array of Hash: #{obj_list.inspect}"}
         
     | 
| 
       328 
341 
     | 
    
         
             
                        # :object_list is an array of hash tables, where key=colum name
         
     | 
| 
       329 
342 
     | 
    
         
             
                        obj_list = obj_list.map{|obj|Flattener.new.flatten(obj)} if @options[:flat_hash]
         
     | 
| 
       330 
343 
     | 
    
         
             
                        display_table(obj_list, compute_fields(obj_list, results[:fields]))
         
     | 
    
        data/lib/aspera/cli/hints.rb
    CHANGED
    
    | 
         @@ -2,6 +2,8 @@ 
     | 
|
| 
       2 
2 
     | 
    
         | 
| 
       3 
3 
     | 
    
         
             
            require 'aspera/fasp/error'
         
     | 
| 
       4 
4 
     | 
    
         
             
            require 'aspera/rest'
         
     | 
| 
      
 5 
     | 
    
         
            +
            require 'aspera/log'
         
     | 
| 
      
 6 
     | 
    
         
            +
            require 'aspera/assert'
         
     | 
| 
       5 
7 
     | 
    
         
             
            require 'net/ssh'
         
     | 
| 
       6 
8 
     | 
    
         
             
            require 'openssl'
         
     | 
| 
       7 
9 
     | 
    
         | 
| 
         @@ -58,14 +60,13 @@ module Aspera 
     | 
|
| 
       58 
60 
     | 
    
         
             
                        matches = hint[:match]
         
     | 
| 
       59 
61 
     | 
    
         
             
                        matches = [matches] unless matches.is_a?(Array)
         
     | 
| 
       60 
62 
     | 
    
         
             
                        matches.each do |m|
         
     | 
| 
      
 63 
     | 
    
         
            +
                          assert_values(m.class, [String, Regexp])
         
     | 
| 
       61 
64 
     | 
    
         
             
                          case m
         
     | 
| 
       62 
65 
     | 
    
         
             
                          when String
         
     | 
| 
       63 
66 
     | 
    
         
             
                            next unless message.eql?(m)
         
     | 
| 
       64 
67 
     | 
    
         
             
                          when Regexp
         
     | 
| 
       65 
68 
     | 
    
         
             
                            next unless message.match?(m)
         
     | 
| 
       66 
     | 
    
         
            -
                          else
         
     | 
| 
       67 
     | 
    
         
            -
                            Log.log.warn("Internal error: hint is a #{m.class}")
         
     | 
| 
       68 
     | 
    
         
            -
                            next
         
     | 
| 
      
 69 
     | 
    
         
            +
                          else error_unexpected_value(m)
         
     | 
| 
       69 
70 
     | 
    
         
             
                          end
         
     | 
| 
       70 
71 
     | 
    
         
             
                          remediation = hint[:remediation]
         
     | 
| 
       71 
72 
     | 
    
         
             
                          remediation = [remediation] unless remediation.is_a?(Array)
         
     | 
    
        data/lib/aspera/cli/main.rb
    CHANGED
    
    | 
         @@ -8,8 +8,10 @@ require 'aspera/cli/transfer_agent' 
     | 
|
| 
       8 
8 
     | 
    
         
             
            require 'aspera/cli/version'
         
     | 
| 
       9 
9 
     | 
    
         
             
            require 'aspera/cli/info'
         
     | 
| 
       10 
10 
     | 
    
         
             
            require 'aspera/cli/hints'
         
     | 
| 
      
 11 
     | 
    
         
            +
            require 'aspera/preview/terminal'
         
     | 
| 
       11 
12 
     | 
    
         
             
            require 'aspera/secret_hider'
         
     | 
| 
       12 
13 
     | 
    
         
             
            require 'aspera/log'
         
     | 
| 
      
 14 
     | 
    
         
            +
            require 'aspera/assert'
         
     | 
| 
       13 
15 
     | 
    
         | 
| 
       14 
16 
     | 
    
         
             
            module Aspera
         
     | 
| 
       15 
17 
     | 
    
         
             
              module Cli
         
     | 
| 
         @@ -53,6 +55,14 @@ module Aspera 
     | 
|
| 
       53 
55 
     | 
    
         
             
                      raise global_status unless global_status.eql?(:success)
         
     | 
| 
       54 
56 
     | 
    
         
             
                      return {type: :object_list, data: status_table}
         
     | 
| 
       55 
57 
     | 
    
         
             
                    end
         
     | 
| 
      
 58 
     | 
    
         
            +
             
     | 
| 
      
 59 
     | 
    
         
            +
                    def result_picture_in_terminal(options, blob)
         
     | 
| 
      
 60 
     | 
    
         
            +
                      terminal_options = options.get_option(:query, default: {}).symbolize_keys
         
     | 
| 
      
 61 
     | 
    
         
            +
                      allowed_options = Preview::Terminal.method(:build).parameters.select{|i|i[0].eql?(:key)}.map{|i|i[1]}
         
     | 
| 
      
 62 
     | 
    
         
            +
                      unknown_options = terminal_options.keys - allowed_options
         
     | 
| 
      
 63 
     | 
    
         
            +
                      raise "invalid options: #{unknown_options.join(', ')}, use #{allowed_options.join(', ')}" unless unknown_options.empty?
         
     | 
| 
      
 64 
     | 
    
         
            +
                      return Main.result_status(Preview::Terminal.build(blob, **terminal_options))
         
     | 
| 
      
 65 
     | 
    
         
            +
                    end
         
     | 
| 
       56 
66 
     | 
    
         
             
                  end # self
         
     | 
| 
       57 
67 
     | 
    
         | 
| 
       58 
68 
     | 
    
         
             
                  private
         
     | 
| 
         @@ -78,9 +88,10 @@ module Aspera 
     | 
|
| 
       78 
88 
     | 
    
         | 
| 
       79 
89 
     | 
    
         
             
                  # This can throw exception if there is a problem with the environment, needs to be caught by execute method
         
     | 
| 
       80 
90 
     | 
    
         
             
                  def init_agents_and_options
         
     | 
| 
       81 
     | 
    
         
            -
                    #  
     | 
| 
       82 
     | 
    
         
            -
                    early_debug_setup
         
     | 
| 
      
 91 
     | 
    
         
            +
                    # create formatter, in case there is an exception, it is used to display.
         
     | 
| 
       83 
92 
     | 
    
         
             
                    @agents[:formatter] = Formatter.new
         
     | 
| 
      
 93 
     | 
    
         
            +
                    # second : manage debug level (allows debugging of option parser)
         
     | 
| 
      
 94 
     | 
    
         
            +
                    early_debug_setup
         
     | 
| 
       84 
95 
     | 
    
         
             
                    @agents[:options] = Manager.new(PROGRAM_NAME)
         
     | 
| 
       85 
96 
     | 
    
         
             
                    # give command line arguments to option manager
         
     | 
| 
       86 
97 
     | 
    
         
             
                    options.parse_command_line(@argv)
         
     | 
| 
         @@ -96,7 +107,7 @@ module Aspera 
     | 
|
| 
       96 
107 
     | 
    
         
             
                    # the Config plugin adds the @preset parser, so declare before TransferAgent which may use it
         
     | 
| 
       97 
108 
     | 
    
         
             
                    @agents[:config] = Plugins::Config.new(@agents, gem: GEM_NAME, name: PROGRAM_NAME, help: DOC_URL, version: Aspera::Cli::VERSION)
         
     | 
| 
       98 
109 
     | 
    
         
             
                    # data persistency
         
     | 
| 
       99 
     | 
    
         
            -
                     
     | 
| 
      
 110 
     | 
    
         
            +
                    assert(@agents[:persistency]){'missing persistency object'}
         
     | 
| 
       100 
111 
     | 
    
         
             
                    # the TransferAgent plugin may use the @preset parser
         
     | 
| 
       101 
112 
     | 
    
         
             
                    @agents[:transfer] = TransferAgent.new(options, config)
         
     | 
| 
       102 
113 
     | 
    
         
             
                    Log.log.debug('plugin env created'.red)
         
     | 
| 
         @@ -219,6 +230,8 @@ module Aspera 
     | 
|
| 
       219 
230 
     | 
    
         
             
                      when /^--log-level=(.*)/ then Aspera::Log.instance.level = Regexp.last_match(1).to_sym
         
     | 
| 
       220 
231 
     | 
    
         
             
                      when /^--logger=(.*)/ then Aspera::Log.instance.logger_type = Regexp.last_match(1).to_sym
         
     | 
| 
       221 
232 
     | 
    
         
             
                      end
         
     | 
| 
      
 233 
     | 
    
         
            +
                    rescue => e
         
     | 
| 
      
 234 
     | 
    
         
            +
                      $stderr.puts("Error: #{e}")
         
     | 
| 
       222 
235 
     | 
    
         
             
                    end
         
     | 
| 
       223 
236 
     | 
    
         
             
                  end
         
     | 
| 
       224 
237 
     | 
    
         |